diff --git a/linden/doc/LICENSE-logos.txt b/linden/doc/LICENSE-logos.txt new file mode 100644 index 000000000..e63c48e54 --- /dev/null +++ b/linden/doc/LICENSE-logos.txt @@ -0,0 +1,23 @@ +COPYRIGHT AND PERMISSION NOTICE + +Second Life(TM) Viewer Artwork. Copyright (C) 2008 Linden Research, Inc. + +Linden Research, Inc. ("Linden Lab") licenses the Second Life viewer +artwork and other works in the files distributed with this Notice under +the Creative Commons Attribution-Share Alike 3.0 License, available at +http://creativecommons.org/licenses/by-sa/3.0/legalcode. For the license +summary, see http://creativecommons.org/licenses/by-sa/3.0/. + +Notwithstanding the foregoing, all of Linden Lab's trademarks, including +but not limited to the Second Life brand name and Second Life Eye-in-Hand +logo, are subject to our trademark policy at +http://secondlife.com/corporate/trademark/. + +If you distribute any copies or adaptations of the Second Life viewer +artwork or any other works in these files, you must include this Notice +and clearly identify any changes made to the original works. Include +this Notice and information where copyright notices are usually included, +for example, after your own copyright notice acknowledging your use of +the Second Life viewer artwork, in a text file distributed with your +program, in your application's About window, or on a credits page for +your work. diff --git a/linden/doc/contributions.txt b/linden/doc/contributions.txt index 2b4010431..9712c6ec7 100644 --- a/linden/doc/contributions.txt +++ b/linden/doc/contributions.txt @@ -80,12 +80,21 @@ Aleric Inglewood IMP-578 IMP-579 IMP-581 + IMP-590 + IMP-592 + IMP-595 IMP-660 IMP-661 IMP-662 IMP-663 IMP-664 IMP-667 + IMP-670 + IMP-688 + IMP-692 + IMP-701 + IMP-712 + IMP-734 Alissa Sabre VWR-81 VWR-83 @@ -334,6 +343,8 @@ Khyota Wulluf Kunnis Basiat VWR-82 VWR-102 +Lance Corrimal + SNOW-717 Lisa Lowe CT-218 CT-219 @@ -461,6 +472,9 @@ Nicholaz Beresford VWR-2412 VWR-2682 VWR-2684 +Nicky Perian + IMP-680 + IMP-685 Nounouch Hapmouche VWR-238 Patric Mills @@ -518,6 +532,7 @@ Robin Cornelius VWR-2488 VWR-9557 VWR-12838 + IMP-595 Ryozu Kojima VWR-53 VWR-287 @@ -598,6 +613,8 @@ TBBle Kurosawa VWR-1892 Teardrops Fall VWR-5366 +Techwolf Lupindo + SNOW-334 tenebrous pau VWR-247 Tharax Ferraris diff --git a/linden/etc/message.xml b/linden/etc/message.xml index f9baf0bfe..0fdf36467 100644 --- a/linden/etc/message.xml +++ b/linden/etc/message.xml @@ -378,14 +378,38 @@ true - ParcelVoiceInfo + WindLightSettingsUpdate + + flavor + llsd + trusted-sender + true + + + ParcelVoiceInfo flavor llsd trusted-sender true + + ParcelMediaURLFilter + + flavor + llsd + trusted-sender + false + + ParcelNavigateMedia + + flavor + llsd + trusted-sender + false + + ParcelObjectOwnersReply flavor diff --git a/linden/indra/CMakeLists.txt b/linden/indra/CMakeLists.txt index 8dca9d8a5..64e0079af 100644 --- a/linden/indra/CMakeLists.txt +++ b/linden/indra/CMakeLists.txt @@ -42,7 +42,6 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llimage) add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj) add_subdirectory(${LIBS_OPEN_PREFIX}llinventory) add_subdirectory(${LIBS_OPEN_PREFIX}llmath) -add_subdirectory(${LIBS_OPEN_PREFIX}llmedia) add_subdirectory(${LIBS_OPEN_PREFIX}llmessage) add_subdirectory(${LIBS_OPEN_PREFIX}llprimitive) add_subdirectory(${LIBS_OPEN_PREFIX}llrender) @@ -59,8 +58,17 @@ endif (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts) add_custom_target(viewer) if (VIEWER) add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger) + add_subdirectory(${LIBS_OPEN_PREFIX}llplugin) add_subdirectory(${LIBS_OPEN_PREFIX}llui) + # viewer media plugins + add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins) + + # llplugin testbed code (is this the right way to include it?) + if (NOT LINUX) + add_subdirectory(${VIEWER_PREFIX}test_apps/llplugintest) + endif (NOT LINUX) + if (LINUX) add_subdirectory(${VIEWER_PREFIX}linux_crash_logger) add_dependencies(viewer linux-crash-logger-strip-target) diff --git a/linden/indra/cmake/00-Common.cmake b/linden/indra/cmake/00-Common.cmake index 032a3cf13..7e85ce0c0 100644 --- a/linden/indra/cmake/00-Common.cmake +++ b/linden/indra/cmake/00-Common.cmake @@ -9,9 +9,9 @@ include(Variables) set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG -DLL_DEBUG=1") set(CMAKE_CXX_FLAGS_RELEASE - "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DNDEBUG") + "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=1 -DNDEBUG") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO - "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") + "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") # Don't bother with a MinSizeRel build. @@ -20,6 +20,14 @@ set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING "Supported build types." FORCE) +# Determine the number of bits of this processor + +if(CMAKE_SIZEOF_VOID_P MATCHES 4) + set( HAVE_64_BIT 0 ) +else(CMAKE_SIZEOF_VOID_P MATCHES 4) + set( HAVE_64_BIT 1 ) +endif(CMAKE_SIZEOF_VOID_P MATCHES 4) + # Platform-specific compilation flags. if (WINDOWS) @@ -186,8 +194,8 @@ if (DARWIN) add_definitions(-DLL_DARWIN=1) set(CMAKE_CXX_LINK_FLAGS "-Wl,-headerpad_max_install_names,-search_paths_first") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_LINK_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlong-branch") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlong-branch") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlong-branch -msse3 -mssse3 -w") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlong-branch -msse3 -mssse3 -w") # NOTE: it's critical that the optimization flag is put in front. # NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered. set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O0 ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") @@ -202,7 +210,7 @@ if (LINUX OR DARWIN) set(GCC_WARNINGS "${GCC_WARNINGS} -Werror") endif (NOT GCC_DISABLE_FATAL_WARNINGS) - set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor") + set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual") set(CMAKE_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}") diff --git a/linden/indra/cmake/APR.cmake b/linden/indra/cmake/APR.cmake index e9f64118d..d1f089891 100644 --- a/linden/indra/cmake/APR.cmake +++ b/linden/indra/cmake/APR.cmake @@ -14,27 +14,27 @@ else (STANDALONE) use_prebuilt_binary(apr_suite) if (WINDOWS) set(APR_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/apr-1.lib - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/apr-1.lib + debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.lib + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.lib ) set(APRICONV_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/apriconv-1.lib - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/apriconv-1.lib + debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapriconv-1.lib + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapriconv-1.lib ) # Doesn't need to link with iconv.dll set(APRICONV_LIBRARIES "") set(APRUTIL_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/aprutil-1.lib ${APRICONV_LIBRARIES} - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/aprutil-1.lib ${APRICONV_LIBRARIES} + debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.lib ${APRICONV_LIBRARIES} + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.lib ${APRICONV_LIBRARIES} ) elseif (DARWIN) set(APR_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.a - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.a + debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.0.3.7.dylib + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.0.3.7.dylib ) set(APRUTIL_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.a - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.a + debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.0.3.8.dylib + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.0.3.8.dylib ) set(APRICONV_LIBRARIES iconv) else (WINDOWS) diff --git a/linden/indra/cmake/BerkeleyDB.cmake b/linden/indra/cmake/BerkeleyDB.cmake index d98e79179..de627638a 100644 --- a/linden/indra/cmake/BerkeleyDB.cmake +++ b/linden/indra/cmake/BerkeleyDB.cmake @@ -6,6 +6,11 @@ set(DB_FIND_REQUIRED ON) if (STANDALONE) include(FindBerkeleyDB) else (STANDALONE) - set(DB_LIBRARIES db-4.2) + if (LINUX) + # Need to add dependency pthread explicitely to support ld.gold. + set(DB_LIBRARIES db-4.2 pthread) + else (LINUX) + set(DB_LIBRARIES db-4.2) + endif (LINUX) set(DB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) endif (STANDALONE) diff --git a/linden/indra/cmake/CopyWinLibs.cmake b/linden/indra/cmake/CopyWinLibs.cmake index b544c15d8..f5846891b 100644 --- a/linden/indra/cmake/CopyWinLibs.cmake +++ b/linden/indra/cmake/CopyWinLibs.cmake @@ -6,6 +6,7 @@ include(CMakeCopyIfDifferent) +# Copying vivox's alut.dll breaks inworld audio, never use it set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-win32") set(vivox_files SLVoice.exe @@ -14,76 +15,23 @@ set(vivox_files ortp.dll wrap_oal.dll ) +copy_if_different( + ${vivox_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/Debug" + out_targets + ${vivox_files} + ) +set(all_targets ${all_targets} ${out_targets}) set(debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug") set(debug_files alut.dll - freebl3.dll - js3250.dll - nspr4.dll - nss3.dll - nssckbi.dll openal32.dll openjpegd.dll libhunspell.dll - plc4.dll - plds4.dll - smime3.dll - softokn3.dll - ssl3.dll - xpcom.dll - xul.dll - windbgdlg.exe - iconv.dll - libxml2.dll - libcairo-2.dll - libfaad-2.dll - libgio-2.0-0.dll - libglib-2.0-0.dll - libgmodule-2.0-0.dll - libgobject-2.0-0.dll - libgthread-2.0-0.dll - charset.dll - intl.dll - libgcrypt-11.dll - libgnutls-26.dll - libgpg-error-0.dll - libgstapp.dll - libgstaudio.dll - libgstaudio-0.10.dll - libgstbase-0.10.dll - libgstcdda.dll - libgstcontroller-0.10.dll - libgstdataprotocol-0.10.dll - libgstdshow.dll - libgstfft.dll - libgstinterfaces.dll - libgstnet-0.10.dll - libgstnetbuffer.dll - libgstpbutils.dll - libgstreamer-0.10.dll - libgstriff.dll - libgstrtp.dll - libgstrtsp.dll - libgstsdp.dll - libgsttag.dll - libgstvideo.dll - libjpeg.dll - libmp3lame-0.dll - libneon-27.dll - libogg-0.dll - liboil-0.3-0.dll - libopenjpeg-2.dll - libpng12-0.dll - libschroedinger-1.0-0.dll - libspeex-1.dll - libtheora-0.dll - libvorbis-0.dll - libvorbisenc-2.dll - libxml2-2.dll - glew32.dll - xvidcore.dll - zlib1.dll + libapr-1.dll + libaprutil-1.dll + libapriconv-1.dll ) copy_if_different( @@ -94,82 +42,179 @@ copy_if_different( ) set(all_targets ${all_targets} ${out_targets}) +# Debug config runtime files required for the plugin test mule +set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug") +set(plugintest_debug_files + libeay32.dll + qtcored4.dll + qtguid4.dll + qtnetworkd4.dll + qtopengld4.dll + qtwebkitd4.dll + qtxmlpatternsd4.dll + ssleay32.dll + ) copy_if_different( - ${vivox_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/Debug" - out_targets - ${vivox_files} + ${plugintest_debug_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/Debug" + out_targets + ${plugintest_debug_files} + ) +set(all_targets ${all_targets} ${out_targets}) + +# Debug config runtime files required for the plugin test mule (Qt image format plugins) +set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug/imageformats") +set(plugintest_debug_files + qgifd4.dll + qicod4.dll + qjpegd4.dll + qmngd4.dll + qsvgd4.dll + qtiffd4.dll + ) +copy_if_different( + ${plugintest_debug_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/Debug/imageformats" + out_targets + ${plugintest_debug_files} + ) +set(all_targets ${all_targets} ${out_targets}) + +copy_if_different( + ${plugintest_debug_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/llplugin/imageformats" + out_targets + ${plugintest_debug_files} + ) +set(all_targets ${all_targets} ${out_targets}) + +# Release & ReleaseDebInfo config runtime files required for the plugin test mule +set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release") +set(plugintest_release_files + libeay32.dll + qtcore4.dll + qtgui4.dll + qtnetwork4.dll + qtopengl4.dll + qtwebkit4.dll + qtxmlpatterns4.dll + ssleay32.dll + ) +copy_if_different( + ${plugintest_release_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/Release" + out_targets + ${plugintest_release_files} + ) +set(all_targets ${all_targets} ${out_targets}) + +copy_if_different( + ${plugintest_release_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/RelWithDebInfo" + out_targets + ${plugintest_release_files} + ) +set(all_targets ${all_targets} ${out_targets}) + +# Release & ReleaseDebInfo config runtime files required for the plugin test mule (Qt image format plugins) +set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release/imageformats") +set(plugintest_release_files + qgif4.dll + qico4.dll + qjpeg4.dll + qmng4.dll + qsvg4.dll + qtiff4.dll + ) +copy_if_different( + ${plugintest_release_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/Release/imageformats" + out_targets + ${plugintest_release_files} + ) +set(all_targets ${all_targets} ${out_targets}) + +copy_if_different( + ${plugintest_release_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/RelWithDebInfo/imageformats" + out_targets + ${plugintest_release_files} + ) +set(all_targets ${all_targets} ${out_targets}) + +copy_if_different( + ${plugintest_release_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/Release/llplugin/imageformats" + out_targets + ${plugintest_release_files} + ) +set(all_targets ${all_targets} ${out_targets}) + +copy_if_different( + ${plugintest_release_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/llplugin/imageformats" + out_targets + ${plugintest_release_files} + ) +set(all_targets ${all_targets} ${out_targets}) + +# Debug config runtime files required for the plugins +set(plugins_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug") +set(plugins_debug_files + libeay32.dll + qtcored4.dll + qtguid4.dll + qtnetworkd4.dll + qtopengld4.dll + qtwebkitd4.dll + qtxmlpatternsd4.dll + ssleay32.dll + ) +copy_if_different( + ${plugins_debug_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/Debug/llplugin" + out_targets + ${plugins_debug_files} + ) +set(all_targets ${all_targets} ${out_targets}) + +# Release & ReleaseDebInfo config runtime files required for the plugins +set(plugins_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release") +set(plugins_release_files + libeay32.dll + qtcore4.dll + qtgui4.dll + qtnetwork4.dll + qtopengl4.dll + qtwebkit4.dll + qtxmlpatterns4.dll + ssleay32.dll + ) +copy_if_different( + ${plugins_release_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/Release/llplugin" + out_targets + ${plugins_release_files} + ) +set(all_targets ${all_targets} ${out_targets}) + +copy_if_different( + ${plugins_release_src_dir} + "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/llplugin" + out_targets + ${plugins_release_files} ) set(all_targets ${all_targets} ${out_targets}) set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release") set(release_files alut.dll - freebl3.dll - js3250.dll - nspr4.dll - nss3.dll - nssckbi.dll openal32.dll openjpeg.dll libhunspell.dll - plc4.dll - plds4.dll - smime3.dll - softokn3.dll - ssl3.dll - xpcom.dll - xul.dll - iconv.dll - libxml2.dll - libcairo-2.dll - libfaad-2.dll - libgio-2.0-0.dll - libglib-2.0-0.dll - libgmodule-2.0-0.dll - libgobject-2.0-0.dll - libgthread-2.0-0.dll - charset.dll - intl.dll - libgcrypt-11.dll - libgnutls-26.dll - libgpg-error-0.dll - libgstapp.dll - libgstaudio.dll - libgstaudio-0.10.dll - libgstbase-0.10.dll - libgstcdda.dll - libgstcontroller-0.10.dll - libgstdataprotocol-0.10.dll - libgstdshow.dll - libgstfft.dll - libgstinterfaces.dll - libgstnet-0.10.dll - libgstnetbuffer.dll - libgstpbutils.dll - libgstreamer-0.10.dll - libgstriff.dll - libgstrtp.dll - libgstrtsp.dll - libgstsdp.dll - libgsttag.dll - libgstvideo.dll - libjpeg.dll - libmp3lame-0.dll - libneon-27.dll - libogg-0.dll - liboil-0.3-0.dll - libopenjpeg-2.dll - libpng12-0.dll - libschroedinger-1.0-0.dll - libspeex-1.dll - libtheora-0.dll - libvorbis-0.dll - libvorbisenc-2.dll - libxml2-2.dll - glew32.dll - xvidcore.dll - zlib1.dll + libapr-1.dll + libaprutil-1.dll + libapriconv-1.dll ) copy_if_different( diff --git a/linden/indra/cmake/DBusGlib.cmake b/linden/indra/cmake/DBusGlib.cmake index dfda0ad0b..b78a0b1e7 100644 --- a/linden/indra/cmake/DBusGlib.cmake +++ b/linden/indra/cmake/DBusGlib.cmake @@ -7,6 +7,7 @@ if (STANDALONE) pkg_check_modules(DBUSGLIB REQUIRED dbus-glib-1) elseif (LINUX) + use_prebuilt_binary(glib) # dbusglib needs glib use_prebuilt_binary(dbusglib) set(DBUSGLIB_FOUND ON FORCE BOOL) set(DBUSGLIB_INCLUDE_DIRS diff --git a/linden/indra/cmake/ExamplePlugin.cmake b/linden/indra/cmake/ExamplePlugin.cmake new file mode 100644 index 000000000..599787ad2 --- /dev/null +++ b/linden/indra/cmake/ExamplePlugin.cmake @@ -0,0 +1,16 @@ +# -*- cmake -*- +include(Linking) +include(Prebuilt) + +if (STANDALONE) + set(EXAMPLEPLUGIN OFF CACHE BOOL + "EXAMPLEPLUGIN support for the llplugin/llmedia test apps.") +else (STANDALONE) + set(EXAMPLEPLUGIN ON CACHE BOOL + "EXAMPLEPLUGIN support for the llplugin/llmedia test apps.") +endif (STANDALONE) + +if (WINDOWS) +elseif (DARWIN) +elseif (LINUX) +endif (WINDOWS) diff --git a/linden/indra/cmake/FindLLQtWebkit.cmake b/linden/indra/cmake/FindLLQtWebkit.cmake new file mode 100644 index 000000000..c747ec32a --- /dev/null +++ b/linden/indra/cmake/FindLLQtWebkit.cmake @@ -0,0 +1,62 @@ +# -*- cmake -*- + +# - Find llqtwebkit +# Find the llqtwebkit includes and library +# This module defines +# LLQTWEBKIT_INCLUDE_DIR, where to find llqtwebkit.h, etc. +# LLQTWEBKIT_LIBRARY, the llqtwebkit library with full path. +# LLQTWEBKIT_FOUND, If false, do not try to use llqtwebkit. +# also defined, but not for general use are +# LLQTWEBKIT_LIBRARIES, the libraries needed to use llqtwebkit. +# LLQTWEBKIT_LIBRARY_DIRS, where to find the llqtwebkit library. +# LLQTWEBKIT_DEFINITIONS - You should add_definitions(${LLQTWEBKIT_DEFINITIONS}) +# before compiling code that includes llqtwebkit library files. + +# Try to use pkg-config first. +# This allows to have two different libllqtwebkit packages installed: +# one for viewer 2.x and one for viewer 1.x. +include(FindPkgConfig) +if (PKG_CONFIG_FOUND) + if (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION) + set(_PACKAGE_ARGS libllqtwebkit>=${LLQtWebkit_FIND_VERSION} REQUIRED) + else (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION) + set(_PACKAGE_ARGS libllqtwebkit) + endif (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION) + if (NOT "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_LESS "2.8") + # As virtually nobody will have a pkg-config file for this, do this check always quiet. + # Unfortunately cmake 2.8 or higher is required for pkg_check_modules to have a 'QUIET'. + set(_PACKAGE_ARGS ${_PACKAGE_ARGS} QUIET) + endif () + pkg_check_modules(LLQTWEBKIT ${_PACKAGE_ARGS}) +endif (PKG_CONFIG_FOUND) +set(LLQTWEBKIT_DEFINITIONS ${LLQTWEBKIT_CFLAGS_OTHER}) + +find_path(LLQTWEBKIT_INCLUDE_DIR llqtwebkit.h NO_SYSTEM_ENVIRONMENT_PATH HINTS ${LLQTWEBKIT_INCLUDE_DIRS}) + +find_library(LLQTWEBKIT_LIBRARY NAMES llqtwebkit NO_SYSTEM_ENVIRONMENT_PATH HINTS ${LLQTWEBKIT_LIBRARY_DIRS}) + +if (NOT PKG_CONFIG_FOUND OR NOT LLQTWEBKIT_FOUND) # If pkg-config couldn't find it, pretend we don't have pkg-config. + set(LLQTWEBKIT_LIBRARIES llqtwebkit) + get_filename_component(LLQTWEBKIT_LIBRARY_DIRS ${LLQTWEBKIT_LIBRARY} PATH) +endif (NOT PKG_CONFIG_FOUND OR NOT LLQTWEBKIT_FOUND) + +# Handle the QUIETLY and REQUIRED arguments and set LLQTWEBKIT_FOUND +# to TRUE if all listed variables are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + LLQTWEBKIT + DEFAULT_MSG + LLQTWEBKIT_LIBRARY + LLQTWEBKIT_INCLUDE_DIR + LLQTWEBKIT_LIBRARIES + LLQTWEBKIT_LIBRARY_DIRS + ) + +mark_as_advanced( + LLQTWEBKIT_LIBRARY + LLQTWEBKIT_INCLUDE_DIR + LLQTWEBKIT_LIBRARIES + LLQTWEBKIT_LIBRARY_DIRS + LLQTWEBKIT_DEFINITIONS + ) + diff --git a/linden/indra/cmake/GStreamer.cmake b/linden/indra/cmake/GStreamer.cmake deleted file mode 100644 index 82c417ae2..000000000 --- a/linden/indra/cmake/GStreamer.cmake +++ /dev/null @@ -1,127 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -if (STANDALONE) - include(FindPkgConfig) - - pkg_check_modules(GSTREAMER REQUIRED gstreamer-0.10) - pkg_check_modules(GSTREAMER_PLUGINS_BASE REQUIRED gstreamer-plugins-base-0.10) - pkg_check_modules(GSTREAMER_VIDEO REQUIRED gstreamer-video-0.10) - -else (STANDALONE) - - # libxml and glib should have their own .cmake files - use_prebuilt_binary(libxml) - use_prebuilt_binary(glib) - - set(GSTREAMER_FOUND ON FORCE BOOL) - set(GSTREAMER_PLUGINS_BASE_FOUND ON FORCE BOOL) - set(GSTREAMER_VIDEO_FOUND ON FORCE BOOL) - - use_prebuilt_binary(gstreamer) - use_prebuilt_binary(gstreamer-plugins) - -if (WINDOWS) - - use_prebuilt_binary(iconv) - set(GSTREAMER_FOUND ON FORCE BOOL) - set(GSTREAMER_INCLUDE_DIRS - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/gio - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/gobject - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/libxml2 - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/iconv - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/gst - ) - - set(GSTREAMER_LIBRARIES - glib-2.0 - gio-2.0 - gmodule-2.0 - gobject-2.0 - gthread-2.0 - libgstvideo.lib - libgsttag.lib - libgstsdp.lib - libgstrtsp.lib - libgstrtp.lib - libgstriff.lib - libgstreamer-0.10.lib - libgstpbutils.lib - libgstnetbuffer.lib - libgstnet-0.10.lib - libgstinterfaces.lib - libgstdshow.lib - libgstdataprotocol-0.10.lib - libgstcontroller-0.10.lib - libgstbase-0.10.lib - libgstaudio.lib - libgstapp.lib - libxml2 - libxml2_a - libxml2_a_dll - iconv - iconv_a - ) - -else (WINDOWS) - - set(GSTREAMER_INCLUDE_DIRS - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/gstreamer-0.10 - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0 - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0/glib - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0/gobject - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/libxml2 - ) - - if (DARWIN) # Mac - - use_prebuilt_binary(flac) - use_prebuilt_binary(liboil) - use_prebuilt_binary(neon) - use_prebuilt_binary(theora) - - set(GSTREAMER_LIBRARIES - gstvideo-0.10 - gstaudio-0.10 - gstbase-0.10 - gstreamer-0.10 - gobject-2.0 - gmodule-2.0 - gthread-2.0 - glib-2.0 - xml2.2 - ) - - else (DARWIN) # Linux - - use_prebuilt_binary(liboil) - use_prebuilt_binary(theora) - - set(GSTREAMER_LIBRARIES - gstvideo-0.10 - gstaudio-0.10 - gstbase-0.10 - gstreamer-0.10 - gobject-2.0 - gmodule-2.0 - dl - gthread-2.0 - rt - glib-2.0 - gio-2.0 - ) - - endif (DARWIN) - -endif (WINDOWS) - -endif (STANDALONE) - -if (GSTREAMER_FOUND AND GSTREAMER_PLUGINS_BASE_FOUND AND GSTREAMER_VIDEO_FOUND) - set(GSTREAMER ON CACHE BOOL "Build with GStreamer streaming media support.") -endif (GSTREAMER_FOUND AND GSTREAMER_PLUGINS_BASE_FOUND AND GSTREAMER_VIDEO_FOUND) - -if (GSTREAMER) - add_definitions(-DLL_GSTREAMER_ENABLED=1) -endif (GSTREAMER) diff --git a/linden/indra/cmake/GStreamer010Plugin.cmake b/linden/indra/cmake/GStreamer010Plugin.cmake new file mode 100644 index 000000000..90ed35c81 --- /dev/null +++ b/linden/indra/cmake/GStreamer010Plugin.cmake @@ -0,0 +1,66 @@ +# -*- cmake -*- +include(Prebuilt) + +if (STANDALONE) + include(FindPkgConfig) + + pkg_check_modules(GSTREAMER010 REQUIRED gstreamer-0.10) + pkg_check_modules(GSTREAMER010_PLUGINS_BASE REQUIRED gstreamer-plugins-base-0.10) + +else (STANDALONE) + + # Possibly libxml and glib should have their own .cmake file instead... + use_prebuilt_binary(glib) # gstreamer needs glib + use_prebuilt_binary(libxml) + use_prebuilt_binary(gstreamer) + set(GSTREAMER010_FOUND ON FORCE BOOL) + set(GSTREAMER010_PLUGINS_BASE_FOUND ON FORCE BOOL) + set(GSTREAMER010_INCLUDE_DIRS + ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/gstreamer-0.10 + ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0 + ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/libxml2 + ) + +endif (STANDALONE) + +if (WINDOWS) + # We don't need to explicitly link against gstreamer itself, because + # LLMediaImplGStreamer probes for the system's copy at runtime. + set(GSTREAMER010_LIBRARIES + libgstvideo + libgstaudio + libgstbase-0.10 + libgstreamer-0.10 + gobject-2.0 + gmodule-2.0 + gthread-2.0 + glib-2.0 + ) +else (WINDOWS) + # We don't need to explicitly link against gstreamer itself, because + # LLMediaImplGStreamer probes for the system's copy at runtime. + set(GSTREAMER010_LIBRARIES + gstvideo-0.10 + gstaudio-0.10 + gstbase-0.10 + gstreamer-0.10 + gobject-2.0 + gmodule-2.0 + dl + gthread-2.0 + rt + glib-2.0 + ) + + +endif (WINDOWS) + + +if (GSTREAMER010_FOUND AND GSTREAMER010_PLUGINS_BASE_FOUND) + set(GSTREAMER010 ON CACHE BOOL "Build with GStreamer-0.10 streaming media support.") + add_definitions(-DLL_GSTREAMER010_ENABLED=1) +endif (GSTREAMER010_FOUND AND GSTREAMER010_PLUGINS_BASE_FOUND) + + + + diff --git a/linden/indra/cmake/Glui.cmake b/linden/indra/cmake/Glui.cmake new file mode 100644 index 000000000..f62a56856 --- /dev/null +++ b/linden/indra/cmake/Glui.cmake @@ -0,0 +1,28 @@ +# -*- cmake -*- +include(Linking) +include(Prebuilt) + +if (STANDALONE) + set(GLUI OFF CACHE BOOL + "GLUI support for the llplugin/llmedia test apps.") +else (STANDALONE) + use_prebuilt_binary(glui) + set(GLUI ON CACHE BOOL + "GLUI support for the llplugin/llmedia test apps.") +endif (STANDALONE) + +if (LINUX) + set(GLUI ON CACHE BOOL + "llplugin media apps HACK for Linux.") +endif (LINUX) + +if (DARWIN OR LINUX) + set(GLUI_LIBRARY + glui) +endif (DARWIN OR LINUX) + +if (WINDOWS) + set(GLUI_LIBRARY + debug glui32.lib + optimized glui32.lib) +endif (WINDOWS) diff --git a/linden/indra/cmake/Glut.cmake b/linden/indra/cmake/Glut.cmake new file mode 100644 index 000000000..314da3065 --- /dev/null +++ b/linden/indra/cmake/Glut.cmake @@ -0,0 +1,19 @@ +# -*- cmake -*- +include(Linking) +include(Prebuilt) + +if (WINDOWS) + use_prebuilt_binary(freeglut) + set(GLUT_LIBRARY + debug freeglut_static.lib + optimized freeglut_static.lib) +endif (WINDOWS) + +if (LINUX) + FIND_LIBRARY(GLUT_LIBRARY glut) +endif (LINUX) + +if (DARWIN) + include(CMakeFindFrameworks) + find_library(GLUT_LIBRARY GLUT) +endif (DARWIN) diff --git a/linden/indra/cmake/LLAudio.cmake b/linden/indra/cmake/LLAudio.cmake index 625e212ca..89b790c6b 100644 --- a/linden/indra/cmake/LLAudio.cmake +++ b/linden/indra/cmake/LLAudio.cmake @@ -1,11 +1,9 @@ # -*- cmake -*- include(Audio) -include(OPENAL) set(LLAUDIO_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llaudio - ${OPENAL_INCLUDE_DIRS} ) set(LLAUDIO_LIBRARIES llaudio ${OPENAL_LIBRARIES}) diff --git a/linden/indra/cmake/LLCommon.cmake b/linden/indra/cmake/LLCommon.cmake index 410766e4f..d87d3c015 100644 --- a/linden/indra/cmake/LLCommon.cmake +++ b/linden/indra/cmake/LLCommon.cmake @@ -7,9 +7,15 @@ include(ZLIB) set(LLCOMMON_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llcommon - ${APRUTIL_INCLUDE_DIR} ${APR_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ) -set(LLCOMMON_LIBRARIES llcommon) +if (LINUX) + # In order to support using ld.gold on linux, we need to explicitely + # specify all libraries that llcommon uses. + # llcommon uses `clock_gettime' which is provided by librt on linux. + set(LLCOMMON_LIBRARIES llcommon rt) +else (LINUX) + set(LLCOMMON_LIBRARIES llcommon) +endif (LINUX) diff --git a/linden/indra/cmake/LLMedia.cmake b/linden/indra/cmake/LLMedia.cmake deleted file mode 100644 index e7769dbd3..000000000 --- a/linden/indra/cmake/LLMedia.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# -*- cmake -*- - -include(GStreamer) - -set(LLMEDIA_INCLUDE_DIRS - ${LIBS_OPEN_DIR}/llmedia - ) - -set(LLMEDIA_LIBRARIES - llmedia - ${GSTREAMER_LIBRARIES} - ${GSTREAMER_PLUGINS_BASE_LIBRARIES} - ${GSTREAMER_VIDEO_LIBRARIES} - ) diff --git a/linden/indra/cmake/LLPlugin.cmake b/linden/indra/cmake/LLPlugin.cmake new file mode 100644 index 000000000..7ee404b9b --- /dev/null +++ b/linden/indra/cmake/LLPlugin.cmake @@ -0,0 +1,14 @@ +# -*- cmake -*- + + +set(LLPLUGIN_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/llplugin + ) + +if (LINUX) + # In order to support using ld.gold on linux, we need to explicitely + # specify all libraries that llplugin uses. + set(LLPLUGIN_LIBRARIES llplugin pthread) +else (LINUX) + set(LLPLUGIN_LIBRARIES llplugin) +endif (LINUX) diff --git a/linden/indra/cmake/MediaPluginBase.cmake b/linden/indra/cmake/MediaPluginBase.cmake new file mode 100644 index 000000000..2be035b64 --- /dev/null +++ b/linden/indra/cmake/MediaPluginBase.cmake @@ -0,0 +1,8 @@ +# -*- cmake -*- + + +set(MEDIA_PLUGIN_BASE_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/media_plugins/base/ + ) + +set(MEDIA_PLUGIN_BASE_LIBRARIES media_plugin_base) diff --git a/linden/indra/cmake/Mozlib.cmake b/linden/indra/cmake/Mozlib.cmake index e9555dfc0..e69de29bb 100644 --- a/linden/indra/cmake/Mozlib.cmake +++ b/linden/indra/cmake/Mozlib.cmake @@ -1,47 +0,0 @@ -# -*- cmake -*- -include(Linking) -include(Prebuilt) - -if (STANDALONE) - set(MOZLIB OFF CACHE BOOL - "Enable Mozilla support in the viewer (requires llmozlib library).") -else (STANDALONE) - use_prebuilt_binary(llmozlib) - set(MOZLIB ON CACHE BOOL - "Enable Mozilla support in the viewer (requires llmozlib library).") -endif (STANDALONE) - -if (MOZLIB) - add_definitions(-DLL_LLMOZLIB_ENABLED=1) - - if (LINUX) - link_directories(${CMAKE_SOURCE_DIR}/newview/app_settings/mozilla-runtime-linux-${ARCH}) - set(MOZLIB_LIBRARIES - llmozlib2 - mozjs - nspr4 - plc4 - plds4 - xpcom - xul - profdirserviceprovider_s - ) - elseif (WINDOWS) - if (MSVC71) - set(MOZLIB_LIBRARIES - debug llmozlib2d - optimized llmozlib2) - elseif (MSVC80 OR MSVC90) - set(MOZLIB_LIBRARIES - debug llmozlib2d-vc80 - optimized llmozlib2-vc80) - endif (MSVC71) - else (LINUX) - set(MOZLIB_LIBRARIES - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libllmozlib2.dylib - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libllmozlib2.dylib - ) - endif (LINUX) -else (MOZLIB) - add_definitions(-DLL_LLMOZLIB_ENABLED=0) -endif (MOZLIB) diff --git a/linden/indra/cmake/PluginAPI.cmake b/linden/indra/cmake/PluginAPI.cmake new file mode 100644 index 000000000..d1649e824 --- /dev/null +++ b/linden/indra/cmake/PluginAPI.cmake @@ -0,0 +1,16 @@ +# -*- cmake -*- + +if (WINDOWS) + set(PLUGIN_API_WINDOWS_LIBRARIES + wsock32 + ws2_32 + psapi + netapi32 + advapi32 + user32 + ) +else (WINDOWS) + set(PLUGIN_API_WINDOWS_LIBRARIES "") +endif (WINDOWS) + + diff --git a/linden/indra/cmake/PulseAudio.cmake b/linden/indra/cmake/PulseAudio.cmake new file mode 100644 index 000000000..f8087a808 --- /dev/null +++ b/linden/indra/cmake/PulseAudio.cmake @@ -0,0 +1,28 @@ +# -*- cmake -*- +include(Prebuilt) + +if (STANDALONE) + include(FindPkgConfig) + + pkg_check_modules(PULSEAUDIO REQUIRED libpulse-mainloop-glib) + +elseif (LINUX) + use_prebuilt_binary(pulseaudio) + set(PULSEAUDIO_FOUND ON FORCE BOOL) + set(PULSEAUDIO_INCLUDE_DIRS + ${LIBS_PREBUILT_DIR}/include + ) + # We don't need to explicitly link against pulseaudio itself, because + # the viewer probes for the system's copy at runtime. + set(PULSEAUDIO_LIBRARIES + # none needed! + ) +endif (STANDALONE) + +if (PULSEAUDIO_FOUND) + set(PULSEAUDIO ON CACHE BOOL "Build with PulseAudio support, if available.") +endif (PULSEAUDIO_FOUND) + +if (PULSEAUDIO) + add_definitions(-DLL_PULSEAUDIO_ENABLED=1) +endif (PULSEAUDIO) diff --git a/linden/indra/cmake/QuickTimePlugin.cmake b/linden/indra/cmake/QuickTimePlugin.cmake new file mode 100644 index 000000000..8afd8f304 --- /dev/null +++ b/linden/indra/cmake/QuickTimePlugin.cmake @@ -0,0 +1,46 @@ +# -*- cmake -*- + +if(INSTALL_PROPRIETARY) + include(Prebuilt) + use_prebuilt_binary(quicktime) +endif(INSTALL_PROPRIETARY) + +if (DARWIN) + include(CMakeFindFrameworks) + find_library(QUICKTIME_LIBRARY QuickTime) +elseif (WINDOWS) + set(QUICKTIME_SDK_DIR "$ENV{PROGRAMFILES}/QuickTime SDK" + CACHE PATH "Location of the QuickTime SDK.") + + find_library(DEBUG_QUICKTIME_LIBRARY qtmlclient + PATHS + ${ARCH_PREBUILT_DIRS_DEBUG} + "${QUICKTIME_SDK_DIR}\\libraries" + ) + + find_library(RELEASE_QUICKTIME_LIBRARY qtmlclient + PATHS + ${ARCH_PREBUILT_DIRS_RELEASE} + "${QUICKTIME_SDK_DIR}\\libraries" + ) + + if (DEBUG_QUICKTIME_LIBRARY AND RELEASE_QUICKTIME_LIBRARY) + set(QUICKTIME_LIBRARY + optimized ${RELEASE_QUICKTIME_LIBRARY} + debug ${DEBUG_QUICKTIME_LIBRARY} + ) + + endif (DEBUG_QUICKTIME_LIBRARY AND RELEASE_QUICKTIME_LIBRARY) + + include_directories( + ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/quicktime + "${QUICKTIME_SDK_DIR}\\CIncludes" + ) +endif (DARWIN) + +mark_as_advanced(QUICKTIME_LIBRARY) + +if (QUICKTIME_LIBRARY) + set(QUICKTIME ON CACHE BOOL "Build with QuickTime streaming media support.") +endif (QUICKTIME_LIBRARY) + diff --git a/linden/indra/cmake/UI.cmake b/linden/indra/cmake/UI.cmake index 9d068c4bf..7a02dff83 100644 --- a/linden/indra/cmake/UI.cmake +++ b/linden/indra/cmake/UI.cmake @@ -31,8 +31,9 @@ if (STANDALONE) add_definitions(${${pkg}_CFLAGS_OTHERS}) endforeach(pkg) else (STANDALONE) - use_prebuilt_binary(gtk-etc) if (LINUX) + use_prebuilt_binary(glib) # gtk-etc needs glib + use_prebuilt_binary(gtk-etc) set(UI_LIBRARIES atk-1.0 cairo diff --git a/linden/indra/cmake/Variables.cmake b/linden/indra/cmake/Variables.cmake index 5d4dffe19..eb9c0044d 100644 --- a/linden/indra/cmake/Variables.cmake +++ b/linden/indra/cmake/Variables.cmake @@ -45,6 +45,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") set(ARCH i686) set(LL_ARCH ${ARCH}_win32) set(LL_ARCH_DIR ${ARCH}-win32) + set(WORD_SIZE 32) endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") @@ -60,17 +61,11 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # set this dynamically from the build system now - # NOTE: wont have a distributable build unless you add this on the configure line with: # -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc' - #set(CMAKE_OSX_ARCHITECTURES i386;ppc) - set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.4u.sdk) - if (CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_ARCHITECTURES MATCHES "ppc") - set(ARCH universal) - else (CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_ARCHITECTURES MATCHES "ppc") - if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "ppc") - set(ARCH ppc) - else (${CMAKE_SYSTEM_PROCESSOR} MATCHES "ppc") - set(ARCH i386) - endif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "ppc") - endif (CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_ARCHITECTURES MATCHES "ppc") + set(CMAKE_OSX_ARCHITECTURES i386) + set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk) + if (CMAKE_OSX_ARCHITECTURES MATCHES "i386") + set(ARCH i386) + endif (CMAKE_OSX_ARCHITECTURES MATCHES "i386") set(LL_ARCH ${ARCH}_darwin) set(LL_ARCH_DIR universal-darwin) endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") diff --git a/linden/indra/cmake/ViewerMiscLibs.cmake b/linden/indra/cmake/ViewerMiscLibs.cmake index 35f4e3aaf..38d044473 100644 --- a/linden/indra/cmake/ViewerMiscLibs.cmake +++ b/linden/indra/cmake/ViewerMiscLibs.cmake @@ -4,10 +4,12 @@ include(Prebuilt) if (NOT STANDALONE) use_prebuilt_binary(libuuid) use_prebuilt_binary(vivox) - if(LINUX AND ${ARCH} STREQUAL "x86_64") + if(LINUX) + if (${ARCH} STREQUAL "x86_64") use_prebuilt_binary(32bitcompatibilitylibs) - endif(LINUX AND ${ARCH} STREQUAL "x86_64") - use_prebuilt_binary(fontconfig) + endif (${ARCH} STREQUAL "x86_64") + use_prebuilt_binary(fontconfig) + endif(LINUX) else (NOT STANDALONE) # Download there even when using standalone. set(STANDALONE OFF) diff --git a/linden/indra/cmake/WebKitLibPlugin.cmake b/linden/indra/cmake/WebKitLibPlugin.cmake new file mode 100644 index 000000000..a4befa495 --- /dev/null +++ b/linden/indra/cmake/WebKitLibPlugin.cmake @@ -0,0 +1,79 @@ +# -*- cmake -*- +include(Linking) +include(Prebuilt) + +if (STANDALONE) + # The minimal version, 4.4.3, is rather arbitrary: it's the version in Debian/Lenny. + find_package(Qt4 4.4.3 COMPONENTS QtCore QtGui QtNetwork QtOpenGL QtWebKit REQUIRED) + include(${QT_USE_FILE}) + set(QTDIR $ENV{QTDIR}) + if (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin") + message(FATAL_ERROR "\"${QT_BINARY_DIR}\" is unequal \"${QTDIR}/bin\"; " + "Qt is found by looking for qmake in your PATH. " + "Please set your PATH such that 'qmake' is found in \$QTDIR/bin, " + "or unset QTDIR if the found Qt is correct.") + endif (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin") + find_package(LLQtWebkit REQUIRED QUIET) + # Add the plugins. + set(QT_PLUGIN_LIBRARIES) + foreach(qlibname qgif qjpeg) + find_library(QT_PLUGIN_${qlibname} ${qlibname} PATHS ${QT_PLUGINS_DIR}/imageformats NO_DEFAULT_PATH) + if (QT_PLUGIN_${qlibname}) + list(APPEND QT_PLUGIN_LIBRARIES ${QT_PLUGIN_${qlibname}}) + else (QT_PLUGIN_${qtlibname}) + message(FATAL_ERROR "Could not find the Qt plugin ${qlibname} in \"${QT_PLUGINS_DIR}/imageformats\"!") + endif (QT_PLUGIN_${qlibname}) + endforeach(qlibname) + # qjpeg depends on libjpeg + list(APPEND QT_PLUGIN_LIBRARIES jpeg) + set(WEBKITLIBPLUGIN OFF CACHE BOOL + "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.") +else (STANDALONE) + use_prebuilt_binary(llqtwebkit) + set(WEBKITLIBPLUGIN ON CACHE BOOL + "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.") +endif (STANDALONE) + +if (WINDOWS) + set(WEBKIT_PLUGIN_LIBRARIES + debug llqtwebkitd + debug QtWebKitd4 + debug QtOpenGLd4 + debug QtNetworkd4 + debug QtGuid4 + debug QtCored4 + debug qtmaind + optimized llqtwebkit + optimized QtWebKit4 + optimized QtOpenGL4 + optimized QtNetwork4 + optimized QtGui4 + optimized QtCore4 + optimized qtmain + ) +elseif (DARWIN) + set(WEBKIT_PLUGIN_LIBRARIES + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib + debug ${ARCH_PREBUILT_DIRS_DEBUG}/libllqtwebkit.dylib + ) +elseif (LINUX) + if (STANDALONE) + set(WEBKIT_PLUGIN_LIBRARIES ${LLQTWEBKIT_LIBRARY} ${QT_LIBRARIES} ${QT_PLUGIN_LIBRARIES}) + else (STANDALONE) + set(WEBKIT_PLUGIN_LIBRARIES + llqtwebkit + qgif + qjpeg + QtWebKit + QtOpenGL + QtNetwork + QtGui + QtCore + jpeg + fontconfig + X11 + Xrender + GL + ) + endif (STANDALONE) +endif (WINDOWS) diff --git a/linden/indra/develop.py b/linden/indra/develop.py index 809ac7823..e80437473 100755 --- a/linden/indra/develop.py +++ b/linden/indra/develop.py @@ -76,6 +76,7 @@ class PlatformSetup(object): build_type = build_types['relwithdebinfo'] standalone = 'OFF' unattended = 'OFF' + universal = 'OFF' project_name = 'Imprudence' distcc = True cmake_opts = [] @@ -404,7 +405,7 @@ def os(self): return 'darwin' def arch(self): - if self.unattended == 'ON': + if self.universal == 'ON': return 'universal' else: return UnixSetup.arch(self) @@ -417,11 +418,11 @@ def cmake_commandline(self, src_dir, build_dir, opts, simple): standalone=self.standalone, unattended=self.unattended, project_name=self.project_name, - universal='', + universal=self.universal, type=self.build_type.upper() ) - if self.unattended == 'ON': - args['universal'] = '-DCMAKE_OSX_ARCHITECTURES:STRING=\'i386;ppc\'' + if self.universal == 'ON': + args['universal'] = '-DCMAKE_OSX_ARCHITECTURES:STRING=\'i386\'' #if simple: # return 'cmake %(opts)s %(dir)r' % args return ('cmake -G %(generator)r ' @@ -696,6 +697,7 @@ def cmake_commandline(self, src_dir, build_dir, opts, simple): --standalone build standalone, without Linden prebuild libraries --unattended build unattended, do not invoke any tools requiring a human response + --universal build a universal binary on Mac OS X (unsupported) -t | --type=NAME build type ("Debug", "Release", or "RelWithDebInfo") -N | --no-distcc disable use of distcc -G | --generator=NAME generator name diff --git a/linden/indra/lib/python/indra/util/llmanifest.py b/linden/indra/lib/python/indra/util/llmanifest.py index 3444a1585..fc777b27a 100644 --- a/linden/indra/lib/python/indra/util/llmanifest.py +++ b/linden/indra/lib/python/indra/util/llmanifest.py @@ -121,6 +121,9 @@ def get_channel(srctree): default=""), dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE), dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE), + dict(name='buildtype', + description='Set to DEBUG if this is a debug build.', + default="RELEASE"), dict(name='channel', description="""The channel to use for updates, packaging, settings name, etc.""", default=get_channel), diff --git a/linden/indra/llaudio/CMakeLists.txt b/linden/indra/llaudio/CMakeLists.txt index 0a668f9e1..1a0527c95 100644 --- a/linden/indra/llaudio/CMakeLists.txt +++ b/linden/indra/llaudio/CMakeLists.txt @@ -4,6 +4,7 @@ project(llaudio) # Current starting point for CMake. Seems rather arbitrary - MC include(00-Common) +include(LLAudio) include(Audio) include(OPENAL) include(FMOD) @@ -12,9 +13,9 @@ include(LLCommon) include(LLMath) include(LLMessage) include(LLVFS) -include(LLMedia) include_directories( + ${LLAUDIO_INCLUDE_DIRS} ${FMOD_INCLUDE_DIR} ${LLCOMMON_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} @@ -26,43 +27,43 @@ include_directories( ${VORBIS_INCLUDE_DIRS} ${OPENAL_LIB_INCLUDE_DIRS} ${FREEAULT_LIB_INCLUDE_DIRS} - ${LLMEDIA_INCLUDE_DIRS} - ${GSTREAMER_INCLUDE_DIRS} ) set(llaudio_SOURCE_FILES - audioengine.cpp - listener.cpp + llaudioengine.cpp + lllistener.cpp llaudiodecodemgr.cpp - vorbisdecode.cpp - vorbisencode.cpp + llvorbisdecode.cpp + llvorbisencode.cpp ) set(llaudio_HEADER_FILES CMakeLists.txt - audioengine.h - listener.h + llaudioengine.h + lllistener.h llaudiodecodemgr.h - vorbisdecode.h - vorbisencode.h - windgen.h + llvorbisdecode.h + llvorbisencode.h + llwindgen.h ) if (FMOD) list(APPEND llaudio_SOURCE_FILES - audioengine_fmod.cpp - listener_fmod.cpp + llaudioengine_fmod.cpp + lllistener_fmod.cpp + llstreamingaudio_fmod.cpp ) list(APPEND llaudio_HEADER_FILES - audioengine_fmod.h - listener_fmod.h + llaudioengine_fmod.h + lllistener_fmod.h + llstreamingaudio_fmod.h ) if (LINUX) if (${CXX_VERSION} MATCHES "4.[23]") - set_source_files_properties(audioengine_fmod.cpp + set_source_files_properties(llaudioengine_fmod.cpp COMPILE_FLAGS -Wno-error=write-strings) endif (${CXX_VERSION} MATCHES "4.[23]") endif (LINUX) @@ -70,13 +71,13 @@ endif (FMOD) if (OPENAL) list(APPEND llaudio_SOURCE_FILES - audioengine_openal.cpp - listener_openal.cpp + llaudioengine_openal.cpp + lllistener_openal.cpp ) list(APPEND llaudio_HEADER_FILES - audioengine_openal.h - listener_openal.h + llaudioengine_openal.h + lllistener_openal.h ) endif (OPENAL) diff --git a/linden/indra/llaudio/listener.cpp b/linden/indra/llaudio/listener.cpp index e2dc30eef..e69de29bb 100644 --- a/linden/indra/llaudio/listener.cpp +++ b/linden/indra/llaudio/listener.cpp @@ -1,153 +0,0 @@ -/** - * @file listener.cpp - * @brief Implementation of LISTENER class abstracting the audio support - * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "listener.h" - -#define DEFAULT_AT 0.0f,0.0f,-1.0f -#define DEFAULT_UP 0.0f,1.0f,0.0f - -//----------------------------------------------------------------------- -// constructor -//----------------------------------------------------------------------- -LLListener::LLListener() -{ - init(); -} - -//----------------------------------------------------------------------- -LLListener::~LLListener() -{ -} - -//----------------------------------------------------------------------- -void LLListener::init(void) -{ - mPosition.zeroVec(); - mListenAt.setVec(DEFAULT_AT); - mListenUp.setVec(DEFAULT_UP); - mVelocity.zeroVec(); -} - -//----------------------------------------------------------------------- -void LLListener::translate(LLVector3 offset) -{ - mPosition += offset; -} - -//----------------------------------------------------------------------- -void LLListener::setPosition(LLVector3 pos) -{ - mPosition = pos; -} - -//----------------------------------------------------------------------- -LLVector3 LLListener::getPosition(void) -{ - return(mPosition); -} - -//----------------------------------------------------------------------- -LLVector3 LLListener::getAt(void) -{ - return(mListenAt); -} - -//----------------------------------------------------------------------- -LLVector3 LLListener::getUp(void) -{ - return(mListenUp); -} - -//----------------------------------------------------------------------- -void LLListener::setVelocity(LLVector3 vel) -{ - mVelocity = vel; -} - -//----------------------------------------------------------------------- -void LLListener::orient(LLVector3 up, LLVector3 at) -{ - mListenUp = up; - mListenAt = at; -} - -//----------------------------------------------------------------------- -void LLListener::set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at) -{ - mPosition = pos; - mVelocity = vel; - - setPosition(pos); - setVelocity(vel); - orient(up,at); -} - -//----------------------------------------------------------------------- -void LLListener::setDopplerFactor(F32 factor) -{ -} - -//----------------------------------------------------------------------- -F32 LLListener::getDopplerFactor() -{ - return (1.f); -} - -//----------------------------------------------------------------------- -void LLListener::setDistanceFactor(F32 factor) -{ -} - -//----------------------------------------------------------------------- -F32 LLListener::getDistanceFactor() -{ - return (1.f); -} - -//----------------------------------------------------------------------- -void LLListener::setRolloffFactor(F32 factor) -{ -} - -//----------------------------------------------------------------------- -F32 LLListener::getRolloffFactor() -{ - return (1.f); -} - -//----------------------------------------------------------------------- -void LLListener::commitDeferredChanges() -{ -} - diff --git a/linden/indra/llaudio/listener.h b/linden/indra/llaudio/listener.h index 4137304e6..e69de29bb 100644 --- a/linden/indra/llaudio/listener.h +++ b/linden/indra/llaudio/listener.h @@ -1,80 +0,0 @@ -/** - * @file listener.h - * @brief Description of LISTENER base class abstracting the audio support. - * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LISTENER_H -#define LL_LISTENER_H - -#include "v3math.h" - -class LLListener -{ - private: - protected: - LLVector3 mPosition; - LLVector3 mVelocity; - LLVector3 mListenAt; - LLVector3 mListenUp; - - public: - - private: - protected: - public: - LLListener(); - virtual ~LLListener(); - virtual void init(); - - virtual void set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at); - - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); - - virtual void orient(LLVector3 up, LLVector3 at); - virtual void translate(LLVector3 offset); - - virtual void setDopplerFactor(F32 factor); - virtual void setDistanceFactor(F32 factor); - virtual void setRolloffFactor(F32 factor); - - virtual LLVector3 getPosition(); - virtual LLVector3 getAt(); - virtual LLVector3 getUp(); - - virtual F32 getDopplerFactor(); - virtual F32 getDistanceFactor(); - virtual F32 getRolloffFactor(); - - virtual void commitDeferredChanges(); -}; - -#endif - diff --git a/linden/indra/llaudio/listener_ds3d.h b/linden/indra/llaudio/listener_ds3d.h index 3121e1254..e69de29bb 100644 --- a/linden/indra/llaudio/listener_ds3d.h +++ b/linden/indra/llaudio/listener_ds3d.h @@ -1,76 +0,0 @@ -/** - * @file listener_ds3d.h - * @brief Description of LISTENER class abstracting the audio support - * as a DirectSound 3D implementation (windows only) - * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LISTENER_DS3D_H -#define LL_LISTENER_DS3D_H - -#include "listener.h" - -#include -#include -#include - -class LLListener_DS3D : public LLListener -{ - private: - protected: - IDirectSound3DListener8 *m3DListener; - public: - - private: - protected: - public: - LLListener_DS3D(); - virtual ~LLListener_DS3D(); - virtual void init(); - - virtual void setDS3DLPtr (IDirectSound3DListener8 *listener_p); - - virtual void translate(LLVector3 offset); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); - virtual void orient(LLVector3 up, LLVector3 at); - - virtual void setDopplerFactor(F32 factor); - virtual F32 getDopplerFactor(); - virtual void setDistanceFactor(F32 factor); - virtual F32 getDistanceFactor(); - virtual void setRolloffFactor(F32 factor); - virtual F32 getRolloffFactor(); - - virtual void commitDeferredChanges(); -}; - -#endif - - diff --git a/linden/indra/llaudio/listener_fmod.cpp b/linden/indra/llaudio/listener_fmod.cpp index 4bbb3d925..e69de29bb 100644 --- a/linden/indra/llaudio/listener_fmod.cpp +++ b/linden/indra/llaudio/listener_fmod.cpp @@ -1,143 +0,0 @@ -/** - * @file listener_fmod.cpp - * @brief implementation of LISTENER class abstracting the audio - * support as a FMOD 3D implementation (windows only) - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "audioengine.h" -#include "listener_fmod.h" -#include "fmod.h" - -//----------------------------------------------------------------------- -// constructor -//----------------------------------------------------------------------- -LLListener_FMOD::LLListener_FMOD() -{ - init(); -} - -//----------------------------------------------------------------------- -LLListener_FMOD::~LLListener_FMOD() -{ -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::init(void) -{ - // do inherited - LLListener::init(); - mDopplerFactor = 1.0f; - mDistanceFactor = 1.0f; - mRolloffFactor = 1.0f; -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::translate(LLVector3 offset) -{ - LLListener::translate(offset); - - FSOUND_3D_Listener_SetAttributes(mPosition.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::setPosition(LLVector3 pos) -{ - LLListener::setPosition(pos); - - FSOUND_3D_Listener_SetAttributes(pos.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::setVelocity(LLVector3 vel) -{ - LLListener::setVelocity(vel); - - FSOUND_3D_Listener_SetAttributes(NULL, vel.mV, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::orient(LLVector3 up, LLVector3 at) -{ - LLListener::orient(up, at); - - // Welcome to the transition between right and left - // (coordinate systems, that is) - // Leaving the at vector alone results in a L/R reversal - // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed - at = -at; - - FSOUND_3D_Listener_SetAttributes(NULL, NULL, at.mV[0],at.mV[1],at.mV[2], up.mV[0],up.mV[1],up.mV[2]); -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::commitDeferredChanges() -{ - FSOUND_Update(); -} - - -void LLListener_FMOD::setRolloffFactor(F32 factor) -{ - mRolloffFactor = factor; - FSOUND_3D_SetRolloffFactor(factor); -} - - -F32 LLListener_FMOD::getRolloffFactor() -{ - return mRolloffFactor; -} - - -void LLListener_FMOD::setDopplerFactor(F32 factor) -{ - mDopplerFactor = factor; - FSOUND_3D_SetDopplerFactor(factor); -} - - -F32 LLListener_FMOD::getDopplerFactor() -{ - return mDopplerFactor; -} - - -void LLListener_FMOD::setDistanceFactor(F32 factor) -{ - mDistanceFactor = factor; - FSOUND_3D_SetDistanceFactor(factor); -} - - -F32 LLListener_FMOD::getDistanceFactor() -{ - return mDistanceFactor; -} diff --git a/linden/indra/llaudio/listener_fmod.h b/linden/indra/llaudio/listener_fmod.h index 5f372ab2c..e69de29bb 100644 --- a/linden/indra/llaudio/listener_fmod.h +++ b/linden/indra/llaudio/listener_fmod.h @@ -1,67 +0,0 @@ -/** - * @file listener_fmod.h - * @brief Description of LISTENER class abstracting the audio support - * as an FMOD 3D implementation (windows and Linux) - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LISTENER_FMOD_H -#define LL_LISTENER_FMOD_H - -#include "listener.h" - -class LLListener_FMOD : public LLListener -{ - public: - LLListener_FMOD(); - virtual ~LLListener_FMOD(); - virtual void init(); - - virtual void translate(LLVector3 offset); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); - virtual void orient(LLVector3 up, LLVector3 at); - virtual void commitDeferredChanges(); - - virtual void setDopplerFactor(F32 factor); - virtual F32 getDopplerFactor(); - virtual void setDistanceFactor(F32 factor); - virtual F32 getDistanceFactor(); - virtual void setRolloffFactor(F32 factor); - virtual F32 getRolloffFactor(); - - protected: - F32 mDopplerFactor; - F32 mDistanceFactor; - F32 mRolloffFactor; -}; - -#endif - - diff --git a/linden/indra/llaudio/llaudiodecodemgr.cpp b/linden/indra/llaudio/llaudiodecodemgr.cpp index afb3c33c0..a14d4ecf2 100644 --- a/linden/indra/llaudio/llaudiodecodemgr.cpp +++ b/linden/indra/llaudio/llaudiodecodemgr.cpp @@ -33,18 +33,18 @@ #include "llaudiodecodemgr.h" -#include "vorbisdecode.h" -#include "audioengine.h" +#include "llvorbisdecode.h" +#include "llaudioengine.h" #include "lllfsthread.h" #include "llvfile.h" #include "llstring.h" #include "lldir.h" #include "llendianswizzle.h" -#include "audioengine.h" #include "llassetstorage.h" #include "vorbis/codec.h" #include "vorbis/vorbisfile.h" +#include "llvorbisencode.h" extern LLAudioEngine *gAudiop; @@ -218,11 +218,42 @@ BOOL LLVorbisDecodeState::initDecode() return(FALSE); } - size_t size_guess = (size_t)ov_pcm_total(&mVF, -1); + S32 sample_count = ov_pcm_total(&mVF, -1); + size_t size_guess = (size_t)sample_count; vorbis_info* vi = ov_info(&mVF, -1); size_guess *= vi->channels; size_guess *= 2; size_guess += 2048; + + bool abort_decode = false; + + if( vi->channels < 1 || vi->channels > LLVORBIS_CLIP_MAX_CHANNELS ) + { + abort_decode = true; + llwarns << "Bad channel count: " << vi->channels << llendl; + } + + if( (size_t)sample_count > LLVORBIS_CLIP_REJECT_SAMPLES ) + { + abort_decode = true; + llwarns << "Illegal sample count: " << sample_count << llendl; + } + + if( size_guess > LLVORBIS_CLIP_REJECT_SIZE ) + { + abort_decode = true; + llwarns << "Illegal sample size: " << size_guess << llendl; + } + + if( abort_decode ) + { + llwarns << "Canceling initDecode. Bad asset: " << mUUID << llendl; + llwarns << "Bad asset encoded by: " << ov_comment(&mVF,-1)->vendor << llendl; + delete mInFilep; + mInFilep = NULL; + return FALSE; + } + mWAVBuffer.reserve(size_guess); mWAVBuffer.resize(WAV_HEADER_SIZE); @@ -375,16 +406,16 @@ BOOL LLVorbisDecodeState::finishDecode() // write "data" chunk length, in little-endian format S32 data_length = mWAVBuffer.size() - WAV_HEADER_SIZE; - mWAVBuffer[40] = (data_length - 8) & 0x000000FF; - mWAVBuffer[41] = ((data_length - 8)>> 8) & 0x000000FF; - mWAVBuffer[42] = ((data_length - 8)>> 16) & 0x000000FF; - mWAVBuffer[43] = ((data_length - 8)>> 24) & 0x000000FF; - + mWAVBuffer[40] = (data_length) & 0x000000FF; + mWAVBuffer[41] = (data_length >> 8) & 0x000000FF; + mWAVBuffer[42] = (data_length >> 16) & 0x000000FF; + mWAVBuffer[43] = (data_length >> 24) & 0x000000FF; // write overall "RIFF" length, in little-endian format - mWAVBuffer[4] = (data_length + 28) & 0x000000FF; - mWAVBuffer[5] = ((data_length + 28) >> 8) & 0x000000FF; - mWAVBuffer[6] = ((data_length + 28) >> 16) & 0x000000FF; - mWAVBuffer[7] = ((data_length + 28) >> 24) & 0x000000FF; + data_length += 36; + mWAVBuffer[4] = (data_length) & 0x000000FF; + mWAVBuffer[5] = (data_length >> 8) & 0x000000FF; + mWAVBuffer[6] = (data_length >> 16) & 0x000000FF; + mWAVBuffer[7] = (data_length >> 24) & 0x000000FF; // // FUDGECAKES!!! Vorbis encode/decode messes up loop point transitions (pop) @@ -396,8 +427,7 @@ BOOL LLVorbisDecodeState::finishDecode() S32 fade_length; char pcmout[4096]; /*Flawfinder: ignore*/ - fade_length = llmin((S32)128,(S32)(data_length)/8); - + fade_length = llmin((S32)128,(S32)(data_length-36)/8); if((S32)mWAVBuffer.size() >= (WAV_HEADER_SIZE + 2* fade_length)) { memcpy(pcmout, &mWAVBuffer[WAV_HEADER_SIZE], (2 * fade_length)); /*Flawfinder: ignore*/ @@ -437,7 +467,7 @@ BOOL LLVorbisDecodeState::finishDecode() } } - if (0 == data_length) + if (36 == data_length) { llwarns << "BAD Vorbis decode in finishDecode!" << llendl; mValid = FALSE; diff --git a/linden/indra/llaudio/audioengine.cpp b/linden/indra/llaudio/llaudioengine.cpp similarity index 85% rename from linden/indra/llaudio/audioengine.cpp rename to linden/indra/llaudio/llaudioengine.cpp index 1900c38ee..bed791afd 100644 --- a/linden/indra/llaudio/audioengine.cpp +++ b/linden/indra/llaudio/llaudioengine.cpp @@ -35,7 +35,8 @@ #include "linden_common.h" -#include "audioengine.h" +#include "llaudioengine.h" +#include "llstreamingaudio.h" #include "llerror.h" #include "llmath.h" @@ -47,9 +48,6 @@ #include "llaudiodecodemgr.h" #include "llassetstorage.h" -#include "llmediamanager.h" -#include "llmediabase.h" -#include "llmediaimplcommon.h" // necessary for grabbing sounds from sim (implemented in viewer) extern void request_sound(const LLUUID &sound_guid); @@ -72,6 +70,15 @@ LLAudioEngine::~LLAudioEngine() { } +LLStreamingAudioInterface* LLAudioEngine::getStreamingAudioImpl() +{ + return mStreamingAudioImpl; +} + +void LLAudioEngine::setStreamingAudioImpl(LLStreamingAudioInterface *impl) +{ + mStreamingAudioImpl = impl; +} void LLAudioEngine::setDefaults() { @@ -98,13 +105,10 @@ void LLAudioEngine::setDefaults() } mMasterGain = 1.f; - mInternetStreamGain = 0.125f; + mInternalGain = 0.f; mNextWindUpdate = 0.f; - mInternetStreamMedia = NULL; - mInternetStreamURL.clear(); - - mStatus = LLMediaBase::STATUS_UNKNOWN; + mStreamingAudioImpl = NULL; for (U32 i = 0; i < LLAudioEngine::AUDIO_TYPE_COUNT; i++) mSecondaryGain[i] = 1.0f; @@ -168,163 +172,61 @@ void LLAudioEngine::shutdown() delete mBuffers[i]; mBuffers[i] = NULL; } - - delete mInternetStreamMedia; - mInternetStreamMedia = NULL; - mInternetStreamURL.clear(); -} - - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -LLMediaBase::EStatus LLAudioEngine::getStatus() -{ - return mStatus; } // virtual void LLAudioEngine::startInternetStream(const std::string& url) { - llinfos << "entered startInternetStream()" << llendl; - - if (!mInternetStreamMedia) - { - LLMediaManager* mgr = LLMediaManager::getInstance(); - if (mgr) - { - mInternetStreamMedia = mgr->createSourceFromMimeType(LLURI(url).scheme(), "audio/mpeg"); // assumes that whatever media implementation supports mp3 also supports vorbis. - llinfos << "mInternetStreamMedia is now " << mInternetStreamMedia << llendl; - } - } - - if(!mInternetStreamMedia) - { - return; - } - // Check for a dead stream from gstreamer, just in case - else if(getStatus() == LLMediaBase::STATUS_DEAD) - { - llinfos << "don't play dead stream urls"<< llendl; - mInternetStreamURL.clear(); - mInternetStreamMedia->addCommand(LLMediaBase::COMMAND_STOP); - mInternetStreamMedia->updateMedia(); - stopInternetStream(); - } - else if (url.empty()) - { - llinfos << "url is emptly. Setting stream to NULL"<< llendl; - mInternetStreamURL.clear(); - mInternetStreamMedia->addCommand(LLMediaBase::COMMAND_STOP); - mInternetStreamMedia->updateMedia(); - } - // Stream appears to be good, attempting to play - else - { - // stop any other stream first - stopInternetStream(); - - llinfos << "Starting internet stream: " << url << llendl; - mInternetStreamURL = url; - mInternetStreamMedia->navigateTo(url); - //llinfos << "Playing....." << llendl; - mInternetStreamMedia->addCommand(LLMediaBase::COMMAND_START); - mInternetStreamMedia->updateMedia(); - mStatus = LLMediaBase::STATUS_STARTED; - } + if (mStreamingAudioImpl) + mStreamingAudioImpl->start(url); } + // virtual void LLAudioEngine::stopInternetStream() { - llinfos << "entered stopInternetStream()" << llendl; - mInternetStreamURL.clear(); - - if(mInternetStreamMedia) - { - if(!mInternetStreamMedia->addCommand(LLMediaBase::COMMAND_STOP)) - { - llinfos << "attempting to stop stream failed!" << llendl; - } - mInternetStreamMedia->updateMedia(); - } - - mInternetStreamURL.clear(); + if (mStreamingAudioImpl) + mStreamingAudioImpl->stop(); } // virtual void LLAudioEngine::pauseInternetStream(int pause) { - llinfos << "entered pauseInternetStream()" << llendl; - - if(!mInternetStreamMedia) - return; - - if(pause) - { - if(! mInternetStreamMedia->addCommand(LLMediaBase::COMMAND_PAUSE)) - { - llinfos << "attempting to pause stream failed!" << llendl; - } - } else { - if(! mInternetStreamMedia->addCommand(LLMediaBase::COMMAND_START)) - { - llinfos << "attempting to unpause stream failed!" << llendl; - } - } - mInternetStreamMedia->updateMedia(); + if (mStreamingAudioImpl) + mStreamingAudioImpl->pause(pause); } // virtual void LLAudioEngine::updateInternetStream() { - if (mInternetStreamMedia) - mInternetStreamMedia->updateMedia(); + if (mStreamingAudioImpl) + mStreamingAudioImpl->update(); } // virtual int LLAudioEngine::isInternetStreamPlaying() { - if (!mInternetStreamMedia) - return 0; - - if (mInternetStreamMedia->getStatus() == LLMediaBase::STATUS_STARTED) - { - return 1; // Active and playing - } - - if (mInternetStreamMedia->getStatus() == LLMediaBase::STATUS_PAUSED) - { - return 2; // paused - } + if (mStreamingAudioImpl) + return mStreamingAudioImpl->isPlaying(); return 0; // Stopped } -// virtual -void LLAudioEngine::getInternetStreamInfo(char* artist, char* title) -{ - artist[0] = 0; - title[0] = 0; -} // virtual void LLAudioEngine::setInternetStreamGain(F32 vol) { - mInternetStreamGain = vol; - - if(!mInternetStreamMedia) - return; - - vol = llclamp(vol, 0.f, 1.f); - mInternetStreamMedia->setVolume(vol); - mInternetStreamMedia->updateMedia(); + if (mStreamingAudioImpl) + mStreamingAudioImpl->setGain(vol); } // virtual -const std::string& LLAudioEngine::getInternetStreamURL() +std::string LLAudioEngine::getInternetStreamURL() { - return mInternetStreamURL; + if (mStreamingAudioImpl) + return mStreamingAudioImpl->getURL(); + else return std::string(); } @@ -335,13 +237,6 @@ void LLAudioEngine::updateChannels() { if (mChannels[i]) { - // set secondary gain if type is available - LLAudioSource* source = mChannels[i]->getSource(); - if (source) - { - mChannels[i]->setSecondaryGain(mSecondaryGain[source->getType()]); - } - mChannels[i]->updateBuffer(); mChannels[i]->update3DPosition(); mChannels[i]->updateLoop(); @@ -361,15 +256,6 @@ void LLAudioEngine::idle(F32 max_decode_time) // Primarily does position updating, cleanup of unused audio sources. // Also does regeneration of the current priority of each audio source. - if (getMuted()) - { - setInternalGain(0.f); - } - else - { - setInternalGain(getMasterGain()); - } - S32 i; for (i = 0; i < MAX_BUFFERS; i++) { @@ -398,6 +284,12 @@ void LLAudioEngine::idle(F32 max_decode_time) continue; } + if (sourcep->isMuted()) + { + ++iter; + continue; + } + if (!sourcep->getChannel() && sourcep->getCurrentBuffer()) { // We could potentially play this sound if its priority is high enough. @@ -420,7 +312,7 @@ void LLAudioEngine::idle(F32 max_decode_time) LLAudioChannel *channelp = getFreeChannel(max_priority); if (channelp) { - //LL_INFOS("AudioEngine") << "Replacing source in channel due to priority!" << llendl; + //llinfos << "Replacing source in channel due to priority!" << llendl; max_sourcep->setChannel(channelp); channelp->setSource(max_sourcep); if (max_sourcep->isSyncSlave()) @@ -453,9 +345,9 @@ void LLAudioEngine::idle(F32 max_decode_time) // attached to each channel, since only those with active channels // can have anything interesting happen with their queue? (Maybe not true) LLAudioSource *sourcep = iter->second; - if (!sourcep->mQueuedDatap) + if (!sourcep->mQueuedDatap || sourcep->isMuted()) { - // Nothing queued, so we don't care. + // Muted, or nothing queued, so we don't care. continue; } @@ -535,6 +427,10 @@ void LLAudioEngine::idle(F32 max_decode_time) for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) { LLAudioSource *sourcep = iter->second; + if (sourcep->isMuted()) + { + continue; + } if (sourcep->isSyncMaster()) { if (sourcep->getPriority() > max_sm_priority) @@ -590,7 +486,7 @@ void LLAudioEngine::idle(F32 max_decode_time) { if (!mBuffers[i]->mInUse && mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > 30.f) { - //LL_INFOS("AudioEngine") << "Flushing unused buffer!" << llendl; + //llinfos << "Flushing unused buffer!" << llendl; mBuffers[i]->mAudioDatap->mBufferp = NULL; delete mBuffers[i]; mBuffers[i] = NULL; @@ -670,7 +566,7 @@ void LLAudioEngine::enableWind(bool enable) } -LLAudioBuffer *LLAudioEngine::getFreeBuffer() +LLAudioBuffer * LLAudioEngine::getFreeBuffer() { static clock_t last_info = 0; static bool spamming = FALSE; @@ -822,15 +718,23 @@ bool LLAudioEngine::isWindEnabled() void LLAudioEngine::setMuted(bool muted) { - mMuted = muted; + if (muted != mMuted) + { + mMuted = muted; + setMasterGain(mMasterGain); + } enableWind(!mMuted); } - void LLAudioEngine::setMasterGain(const F32 gain) { mMasterGain = gain; - setInternalGain(gain); + F32 internal_gain = getMuted() ? 0.f : gain; + if (internal_gain != mInternalGain) + { + mInternalGain = internal_gain; + setInternalGain(mInternalGain); + } } F32 LLAudioEngine::getMasterGain() @@ -852,7 +756,10 @@ F32 LLAudioEngine::getSecondaryGain(S32 type) F32 LLAudioEngine::getInternetStreamGain() { - return mInternetStreamGain; + if (mStreamingAudioImpl) + return mStreamingAudioImpl->getGain(); + else + return 1.0f; } void LLAudioEngine::setMaxWindGain(F32 gain) @@ -929,10 +836,9 @@ void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_i const S32 type, const LLVector3d &pos_global) { // Create a new source (since this can't be associated with an existing source. - //LL_INFOS("AudioEngine") << "Localized: " << audio_uuid << llendl; + //llinfos << "Localized: " << audio_uuid << llendl; - //If we cannot hear it, dont even try to load the sound. - if (mMuted || gain == 0.0) + if (mMuted) { return; } @@ -1020,28 +926,6 @@ F32 LLAudioEngine::getDopplerFactor() } -void LLAudioEngine::setDistanceFactor(F32 factor) -{ - if (mListenerp) - { - mListenerp->setDistanceFactor(factor); - } -} - - -F32 LLAudioEngine::getDistanceFactor() -{ - if (mListenerp) - { - return mListenerp->getDistanceFactor(); - } - else - { - return 0.f; - } -} - - void LLAudioEngine::setRolloffFactor(F32 factor) { if (mListenerp) @@ -1070,7 +954,7 @@ void LLAudioEngine::commitDeferredChanges() } -LLAudioSource *LLAudioEngine::findAudioSource(const LLUUID &source_id) +LLAudioSource * LLAudioEngine::findAudioSource(const LLUUID &source_id) { source_map::iterator iter; iter = mAllSources.find(source_id); @@ -1086,7 +970,7 @@ LLAudioSource *LLAudioEngine::findAudioSource(const LLUUID &source_id) } -LLAudioData *LLAudioEngine::getAudioData(const LLUUID &audio_uuid) +LLAudioData * LLAudioEngine::getAudioData(const LLUUID &audio_uuid) { data_map::iterator iter; iter = mAllData.find(audio_uuid); @@ -1152,10 +1036,10 @@ bool LLAudioEngine::hasLocalFile(const LLUUID &uuid) void LLAudioEngine::startNextTransfer() { - //LL_INFOS("AudioEngine") << "LLAudioEngine::startNextTransfer()" << llendl; + //llinfos << "LLAudioEngine::startNextTransfer()" << llendl; if (mCurrentTransfer.notNull() || getMuted()) { - //LL_INFOS("AudioEngine") << "Transfer in progress, aborting" << llendl; + //llinfos << "Transfer in progress, aborting" << llendl; return; } @@ -1336,7 +1220,7 @@ void LLAudioEngine::startNextTransfer() if (asset_id.notNull()) { - LL_INFOS("AudioEngine") << "Getting asset data for: " << asset_id << llendl; + llinfos << "Getting asset data for: " << asset_id << llendl; gAudiop->mCurrentTransfer = asset_id; gAudiop->mCurrentTransferTimer.reset(); gAssetStorage->getAssetData(asset_id, LLAssetType::AT_SOUND, @@ -1344,7 +1228,7 @@ void LLAudioEngine::startNextTransfer() } else { - //LL_INFOS("AudioEngine") << "No pending transfers?" << llendl; + //llinfos << "No pending transfers?" << llendl; } } @@ -1354,7 +1238,7 @@ void LLAudioEngine::assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::E { if (result_code) { - LL_INFOS("AudioEngine") << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << llendl; + llinfos << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << llendl; // Need to mark data as bad to avoid constant rerequests. LLAudioData *adp = gAudiop->getAudioData(uuid); if (adp) @@ -1394,13 +1278,14 @@ LLAudioSource::LLAudioSource(const LLUUID& id, const LLUUID& owner_id, const F32 mOwnerID(owner_id), mPriority(0.f), mGain(gain), - mType(type), + mSourceMuted(false), mAmbient(false), mLoop(false), mSyncMaster(false), mSyncSlave(false), mQueueSounds(false), mPlayedOnce(false), + mType(type), mChannelp(NULL), mCurrentDatap(NULL), mQueuedDatap(NULL) @@ -1452,6 +1337,10 @@ void LLAudioSource::updatePriority() { mPriority = 1.f; } + else if (isMuted()) + { + mPriority = 0.f; + } else { // Priority is based on distance @@ -1500,25 +1389,33 @@ bool LLAudioSource::setupChannel() bool LLAudioSource::play(const LLUUID &audio_uuid) { + // Special abuse of play(); don't play a sound, but kill it. if (audio_uuid.isNull()) { if (getChannel()) { getChannel()->setSource(NULL); setChannel(NULL); - addAudioData(NULL, true); + if (!isMuted()) + { + mCurrentDatap = NULL; + } } + return false; } + // Reset our age timeout if someone attempts to play the source. mAgeTimer.reset(); LLAudioData *adp = gAudiop->getAudioData(audio_uuid); - - bool has_buffer = gAudiop->updateBufferForData(adp, audio_uuid); - - addAudioData(adp); + if (isMuted()) + { + return false; + } + + bool has_buffer = gAudiop->updateBufferForData(adp, audio_uuid); if (!has_buffer) { // Don't bother trying to set up a channel or anything, we don't have an audio buffer. @@ -1543,10 +1440,11 @@ bool LLAudioSource::play(const LLUUID &audio_uuid) } -bool LLAudioSource::isDone() +bool LLAudioSource::isDone() const { const F32 MAX_AGE = 60.f; const F32 MAX_UNPLAYED_AGE = 15.f; + const F32 MAX_MUTED_AGE = 11.f; if (isLoop()) { @@ -1554,7 +1452,6 @@ bool LLAudioSource::isDone() return false; } - if (hasPendingPreloads()) { return false; @@ -1571,10 +1468,10 @@ bool LLAudioSource::isDone() // This is a single-play source if (!mChannelp) { - if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce) + if ((elapsed > (mSourceMuted ? MAX_MUTED_AGE : MAX_UNPLAYED_AGE)) || mPlayedOnce) { // We don't have a channel assigned, and it's been - // over 5 seconds since we tried to play it. Don't bother. + // over 15 seconds since we tried to play it. Don't bother. //llinfos << "No channel assigned, source is done" << llendl; return true; } @@ -1600,7 +1497,7 @@ bool LLAudioSource::isDone() if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce) { - // The sound isn't playing back after 5 seconds or we're already done playing it, kill it. + // The sound isn't playing back after 15 seconds or we're already done playing it, kill it. return true; } @@ -1696,17 +1593,17 @@ bool LLAudioSource::hasPendingPreloads() const } -LLAudioData *LLAudioSource::getCurrentData() +LLAudioData * LLAudioSource::getCurrentData() { return mCurrentDatap; } -LLAudioData *LLAudioSource::getQueuedData() +LLAudioData * LLAudioSource::getQueuedData() { return mQueuedDatap; } -LLAudioBuffer *LLAudioSource::getCurrentBuffer() +LLAudioBuffer * LLAudioSource::getCurrentBuffer() { if (!mCurrentDatap) { @@ -1737,7 +1634,7 @@ LLAudioChannel::LLAudioChannel() : LLAudioChannel::~LLAudioChannel() { // Need to disconnect any sources which are using this channel. - //LL_INFOS("AudioEngine") << "Cleaning up audio channel" << llendl; + //llinfos << "Cleaning up audio channel" << llendl; if (mCurrentSourcep) { mCurrentSourcep->setChannel(NULL); @@ -1748,12 +1645,12 @@ LLAudioChannel::~LLAudioChannel() void LLAudioChannel::setSource(LLAudioSource *sourcep) { - //LL_INFOS("AudioEngine") << this << ": setSource(" << sourcep << ")" << llendl; + //llinfos << this << ": setSource(" << sourcep << ")" << llendl; if (!sourcep) { // Clearing the source for this channel, don't need to do anything. - //LL_INFOS("AudioEngine") << "Clearing source for channel" << llendl; + //llinfos << "Clearing source for channel" << llendl; cleanup(); mCurrentSourcep = NULL; mWaiting = false; @@ -1763,7 +1660,7 @@ void LLAudioChannel::setSource(LLAudioSource *sourcep) if (sourcep == mCurrentSourcep) { // Don't reallocate the channel, this will make FMOD goofy. - //LL_INFOS("AudioEngine") << "Calling setSource with same source!" << llendl; + //llinfos << "Calling setSource with same source!" << llendl; } mCurrentSourcep = sourcep; diff --git a/linden/indra/llaudio/audioengine.h b/linden/indra/llaudio/llaudioengine.h similarity index 92% rename from linden/indra/llaudio/audioengine.h rename to linden/indra/llaudio/llaudioengine.h index e46091c57..a1b240eea 100644 --- a/linden/indra/llaudio/audioengine.h +++ b/linden/indra/llaudio/llaudioengine.h @@ -37,18 +37,14 @@ #include #include -#include "listener.h" #include "v3math.h" #include "v3dmath.h" -#include "listener.h" #include "lltimer.h" #include "lluuid.h" #include "llframetimer.h" #include "llassettype.h" -#include "llmediabase.h" - -class LLMediaBase; +#include "lllistener.h" const F32 LL_WIND_UPDATE_INTERVAL = 0.1f; const F32 LL_ROLLOFF_MULTIPLIER_UNDER_WATER = 5.f; // How much sounds are weaker under water @@ -75,7 +71,7 @@ class LLAudioData; class LLAudioChannel; class LLAudioChannelOpenAL; class LLAudioBuffer; - +class LLStreamingAudioInterface; // @@ -121,9 +117,11 @@ class LLAudioEngine // Use these for temporarily muting the audio system. // Does not change buffers, initialization, etc. but // stops playing new sounds. - virtual void setMuted(bool muted); - virtual bool getMuted() const { return mMuted; } - + void setMuted(bool muted); + bool getMuted() const { return mMuted; } +#ifdef USE_PLUGIN_MEDIA + LLPluginClassMedia* initializeMedia(const std::string& media_type); +#endif F32 getMasterGain(); void setMasterGain(F32 gain); @@ -134,8 +132,6 @@ class LLAudioEngine virtual void setDopplerFactor(F32 factor); virtual F32 getDopplerFactor(); - virtual void setDistanceFactor(F32 factor); - virtual F32 getDistanceFactor(); virtual void setRolloffFactor(F32 factor); virtual F32 getRolloffFactor(); virtual void setMaxWindGain(F32 gain); @@ -154,19 +150,19 @@ class LLAudioEngine LLAudioSource *findAudioSource(const LLUUID &source_id); LLAudioData *getAudioData(const LLUUID &audio_uuid); - - // Internet stream methods - virtual void startInternetStream(const std::string& url); - virtual void stopInternetStream(); - virtual void pauseInternetStream(int pause); - virtual void updateInternetStream(); - virtual int isInternetStreamPlaying(); - virtual void getInternetStreamInfo(char* artist, char* title); + // Internet stream implementation manipulation + LLStreamingAudioInterface *getStreamingAudioImpl(); + void setStreamingAudioImpl(LLStreamingAudioInterface *impl); + // Internet stream methods - these will call down into the *mStreamingAudioImpl if it exists + void startInternetStream(const std::string& url); + void stopInternetStream(); + void pauseInternetStream(int pause); + void updateInternetStream(); // expected to be called often + int isInternetStreamPlaying(); // use a value from 0.0 to 1.0, inclusive - virtual void setInternetStreamGain(F32 vol); - virtual const std::string& getInternetStreamURL(); - virtual LLMediaBase::EStatus getStatus(); - + void setInternetStreamGain(F32 vol); + std::string getInternetStreamURL(); + // For debugging usage virtual LLVector3 getListenerPos(); @@ -185,8 +181,6 @@ class LLAudioEngine static void assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code, LLExtStat ext_status); friend class LLPipeline; // For debugging - - LLMediaBase * getStreamMedia() { return mInternetStreamMedia; } public: F32 mMaxWindGain; // Hack. Public to set before fade in? @@ -244,21 +238,16 @@ class LLAudioEngine LLAudioBuffer *mBuffers[MAX_BUFFERS]; F32 mMasterGain; + F32 mInternalGain; // Actual gain set; either mMasterGain or 0 when mMuted is true. F32 mSecondaryGain[AUDIO_TYPE_COUNT]; - // Hack! Internet streams are treated differently from other sources! - F32 mInternetStreamGain; - std::string mInternetStreamURL; - F32 mNextWindUpdate; LLFrameTimer mWindUpdateTimer; - LLMediaBase::EStatus mStatus; - private: void setDefaults(); - LLMediaBase *mInternetStreamMedia; + LLStreamingAudioInterface *mStreamingAudioImpl; }; @@ -314,7 +303,8 @@ class LLAudioSource virtual void setGain(const F32 gain) { mGain = llclamp(gain, 0.f, 1.f); } const LLUUID &getID() const { return mID; } - bool isDone(); + bool isDone() const; + bool isMuted() const { return mSourceMuted; } LLAudioData *getCurrentData(); LLAudioData *getQueuedData(); @@ -336,6 +326,7 @@ class LLAudioSource LLUUID mOwnerID; // owner of the object playing the sound F32 mPriority; F32 mGain; + bool mSourceMuted; bool mAmbient; bool mLoop; bool mSyncMaster; diff --git a/linden/indra/llaudio/audioengine_fmod.cpp b/linden/indra/llaudio/llaudioengine_fmod.cpp similarity index 71% rename from linden/indra/llaudio/audioengine_fmod.cpp rename to linden/indra/llaudio/llaudioengine_fmod.cpp index 938c2aa2d..85ae86352 100644 --- a/linden/indra/llaudio/audioengine_fmod.cpp +++ b/linden/indra/llaudio/llaudioengine_fmod.cpp @@ -32,8 +32,11 @@ #include "linden_common.h" -#include "audioengine_fmod.h" -#include "listener_fmod.h" +#include "llstreamingaudio.h" +#include "llstreamingaudio_fmod.h" + +#include "llaudioengine_fmod.h" +#include "lllistener_fmod.h" #include "llerror.h" #include "llmath.h" @@ -46,6 +49,7 @@ #include "sound_ids.h" + extern "C" { void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata); } @@ -53,35 +57,9 @@ extern "C" { FSOUND_DSPUNIT *gWindDSP = NULL; -// Safe strcpy -#if 0 //(unused) //LL_WINDOWS || LL_LINUX -static size_t strlcpy( char* dest, const char* src, size_t dst_size ) -{ - size_t source_len = 0; - size_t min_len = 0; - if( dst_size > 0 ) - { - if( src ) - { - source_len = strlen(src); /*Flawfinder: ignore*/ - min_len = llmin( dst_size - 1, source_len ); - memcpy(dest, src, min_len); /*Flawfinder: ignore*/ - } - dest[min_len] = '\0'; - } - return source_len; -} -#else -// apple ships with the non-standard strlcpy in /usr/include/string.h: -// size_t strlcpy(char *, const char *, size_t); -#endif - - LLAudioEngine_FMOD::LLAudioEngine_FMOD() { mInited = false; - mCurrentInternetStreamp = NULL; - mInternetStreamChannel = -1; mWindGen = NULL; } @@ -93,8 +71,6 @@ LLAudioEngine_FMOD::~LLAudioEngine_FMOD() bool LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata) { - mFadeIn = -10000; - LLAudioEngine::init(num_channels, userdata); // Reserve one extra channel for the http stream. @@ -241,7 +217,9 @@ bool LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata) #endif - initInternetStream(); + // set up our favourite FMOD-native streaming audio implementation if none has already been added + if (!getStreamingAudioImpl()) // no existing implementation added + setStreamingAudioImpl(new LLStreamingAudio_FMOD()); LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() FMOD initialized correctly" << LL_ENDL; @@ -296,13 +274,13 @@ void LLAudioEngine_FMOD::shutdown() } -LLAudioBuffer *LLAudioEngine_FMOD::createBuffer() +LLAudioBuffer * LLAudioEngine_FMOD::createBuffer() { return new LLAudioBufferFMOD(); } -LLAudioChannel *LLAudioEngine_FMOD::createChannel() +LLAudioChannel * LLAudioEngine_FMOD::createChannel() { return new LLAudioChannelFMOD(); } @@ -432,10 +410,12 @@ void LLAudioEngine_FMOD::setInternalGain(F32 gain) gain = llclamp( gain, 0.0f, 1.0f ); FSOUND_SetSFXMasterVolume( llround( 255.0f * gain ) ); - if ( mInternetStreamChannel != -1 ) + LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); + if ( saimpl ) { - F32 clamp_internet_stream_gain = llclamp( mInternetStreamGain, 0.0f, 1.0f ); - FSOUND_SetVolumeAbsolute( mInternetStreamChannel, llround( 255.0f * clamp_internet_stream_gain ) ); + // fmod likes its streaming audio channel gain re-asserted after + // master volume change. + saimpl->setGain(saimpl->getGain()); } } @@ -660,7 +640,7 @@ bool LLAudioBufferFMOD::loadWAV(const std::string& filename) return false; } - if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) + if (!LLAPRFile::isExist(filename, LL_APR_RPB)) { // File not found, abort. return false; @@ -752,313 +732,6 @@ void LLAudioBufferFMOD::set3DMode(bool use3d) } - -//--------------------------------------------------------------------------- -// Internet Streaming -//--------------------------------------------------------------------------- -void LLAudioEngine_FMOD::initInternetStream() -{ - // Number of milliseconds of audio to buffer for the audio card. - // Must be larger than the usual Second Life frame stutter time. - FSOUND_Stream_SetBufferSize(200); - - // Here's where we set the size of the network buffer and some buffering - // parameters. In this case we want a network buffer of 16k, we want it - // to prebuffer 40% of that when we first connect, and we want it - // to rebuffer 80% of that whenever we encounter a buffer underrun. - - // Leave the net buffer properties at the default. - //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80); - mInternetStreamURL.clear(); -} - - -void LLAudioEngine_FMOD::startInternetStream(const std::string& url) -{ - if (!mInited) - { - llwarns << "startInternetStream before audio initialized" << llendl; - return; - } - - // "stop" stream but don't clear url, etc. in calse url == mInternetStreamURL - stopInternetStream(); - if (!url.empty()) - { - llinfos << "Starting internet stream: " << url << llendl; - mCurrentInternetStreamp = new LLAudioStreamFMOD(url); - mInternetStreamURL = url; - } - else - { - llinfos << "Set internet stream to null" << llendl; - mInternetStreamURL.clear(); - } -} - - -signed char F_CALLBACKAPI LLAudioEngine_FMOD::callbackMetaData(char *name, char *value, void *userdata) -{ - /* - LLAudioEngine_FMOD* self = (LLAudioEngine_FMOD*)userdata; - - if (!strcmp("ARTIST", name)) - { - strlcpy(self->mInternetStreamArtist, value, 256); - self->mInternetStreamNewMetaData = true; - return true; - } - - if (!strcmp("TITLE", name)) - { - strlcpy(self->mInternetStreamTitle, value, 256); - self->mInternetStreamNewMetaData = true; - return true; - } - */ - - return true; -} - - -void LLAudioEngine_FMOD::updateInternetStream() -{ - // Kill dead internet streams, if possible - std::list::iterator iter; - for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) - { - LLAudioStreamFMOD *streamp = *iter; - if (streamp->stopStream()) - { - llinfos << "Closed dead stream" << llendl; - delete streamp; - mDeadStreams.erase(iter++); - } - else - { - iter++; - } - } - - // Don't do anything if there are no streams playing - if (!mCurrentInternetStreamp) - { - return; - } - - int open_state = mCurrentInternetStreamp->getOpenState(); - - if (!open_state) - { - // Stream is live - - - // start the stream if it's ready - if (mInternetStreamChannel < 0) - { - mInternetStreamChannel = mCurrentInternetStreamp->startStream(); - - if (mInternetStreamChannel != -1) - { - // Reset volume to previously set volume - setInternetStreamGain(mInternetStreamGain); - FSOUND_SetPaused(mInternetStreamChannel, false); - //FSOUND_Stream_Net_SetMetadataCallback(mInternetStream, callbackMetaData, this); - } - } - } - - switch(open_state) - { - default: - case 0: - // success - break; - case -1: - // stream handle is invalid - llwarns << "InternetStream - invalid handle" << llendl; - stopInternetStream(); - return; - case -2: - // opening - //strlcpy(mInternetStreamArtist, "Opening", 256); - break; - case -3: - // failed to open, file not found, perhaps - llwarns << "InternetSteam - failed to open" << llendl; - stopInternetStream(); - return; - case -4: - // connecting - //strlcpy(mInternetStreamArtist, "Connecting", 256); - break; - case -5: - // buffering - //strlcpy(mInternetStreamArtist, "Buffering", 256); - break; - } - -} - -void LLAudioEngine_FMOD::stopInternetStream() -{ - if (mInternetStreamChannel != -1) - { - FSOUND_SetPaused(mInternetStreamChannel, true); - FSOUND_SetPriority(mInternetStreamChannel, 0); - mInternetStreamChannel = -1; - } - - if (mCurrentInternetStreamp) - { - llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl; - if (mCurrentInternetStreamp->stopStream()) - { - delete mCurrentInternetStreamp; - } - else - { - llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl; - mDeadStreams.push_back(mCurrentInternetStreamp); - } - mCurrentInternetStreamp = NULL; - //mInternetStreamURL.clear(); - } -} - -void LLAudioEngine_FMOD::pauseInternetStream(int pause) -{ - if (pause < 0) - { - pause = mCurrentInternetStreamp ? 1 : 0; - } - - if (pause) - { - if (mCurrentInternetStreamp) - { - stopInternetStream(); - } - } - else - { - startInternetStream(mInternetStreamURL); - } -} - - -// A stream is "playing" if it has been requested to start. That -// doesn't necessarily mean audio is coming out of the speakers. -int LLAudioEngine_FMOD::isInternetStreamPlaying() -{ - if (mCurrentInternetStreamp) - { - return 1; // Active and playing - } - else if (!mInternetStreamURL.empty()) - { - return 2; // "Paused" - } - else - { - return 0; - } -} - - -void LLAudioEngine_FMOD::setInternetStreamGain(F32 vol) -{ - mInternetStreamGain = vol; - - if (mInternetStreamChannel != -1) - { - vol = llclamp(vol, 0.f, 1.f); - int vol_int = llround(vol * 255.f); - FSOUND_SetVolumeAbsolute(mInternetStreamChannel, vol_int); - } -} - - -LLAudioStreamFMOD::LLAudioStreamFMOD(const std::string& url) : - mInternetStream(NULL), - mReady(false) -{ - mInternetStreamURL = url; - mInternetStream = FSOUND_Stream_Open(url.c_str(), FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); - if (!mInternetStream) - { - llwarns << "Couldn't open fmod stream, error " - << FMOD_ErrorString(FSOUND_GetError()) - << llendl; - mReady = false; - return; - } - - mReady = true; -} - -int LLAudioStreamFMOD::startStream() -{ - // We need a live and opened stream before we try and play it. - if (!mInternetStream || getOpenState()) - { - llwarns << "No internet stream to start playing!" << llendl; - return -1; - } - - // Make sure the stream is set to 2D mode. - FSOUND_Stream_SetMode(mInternetStream, FSOUND_2D); - - return FSOUND_Stream_PlayEx(FSOUND_FREE, mInternetStream, NULL, true); -} - -bool LLAudioStreamFMOD::stopStream() -{ - if (mInternetStream) - { - int read_percent = 0; - int status = 0; - int bitrate = 0; - unsigned int flags = 0x0; - FSOUND_Stream_Net_GetStatus(mInternetStream, &status, &read_percent, &bitrate, &flags); - - bool close = true; - switch (status) - { - case FSOUND_STREAM_NET_CONNECTING: - close = false; - break; - case FSOUND_STREAM_NET_NOTCONNECTED: - case FSOUND_STREAM_NET_BUFFERING: - case FSOUND_STREAM_NET_READY: - case FSOUND_STREAM_NET_ERROR: - default: - close = true; - } - - if (close) - { - FSOUND_Stream_Close(mInternetStream); - mInternetStream = NULL; - return true; - } - else - { - return false; - } - } - else - { - return true; - } -} - -int LLAudioStreamFMOD::getOpenState() -{ - int open_state = FSOUND_Stream_GetOpenState(mInternetStream); - return open_state; -} - void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata) { // originalbuffer = fmod's original mixbuffer. diff --git a/linden/indra/llaudio/audioengine_fmod.h b/linden/indra/llaudio/llaudioengine_fmod.h similarity index 77% rename from linden/indra/llaudio/audioengine_fmod.h rename to linden/indra/llaudio/llaudioengine_fmod.h index d0d2e1bc3..3968657cb 100644 --- a/linden/indra/llaudio/audioengine_fmod.h +++ b/linden/indra/llaudio/llaudioengine_fmod.h @@ -34,13 +34,13 @@ #ifndef LL_AUDIOENGINE_FMOD_H #define LL_AUDIOENGINE_FMOD_H -#include "audioengine.h" -#include "listener_fmod.h" -#include "windgen.h" +#include "llaudioengine.h" +#include "lllistener_fmod.h" +#include "llwindgen.h" #include "fmod.h" -class LLAudioStreamFMOD; +class LLAudioStreamManagerFMOD; class LLAudioEngine_FMOD : public LLAudioEngine { @@ -50,20 +50,11 @@ class LLAudioEngine_FMOD : public LLAudioEngine // initialization/startup/shutdown virtual bool init(const S32 num_channels, void *user_data); - virtual std::string getDriverName(bool verbose); + virtual std::string getDriverName(bool verbose); virtual void allocateListener(); virtual void shutdown(); - // Internet stream methods - virtual void initInternetStream(); - virtual void startInternetStream(const std::string& url); - virtual void updateInternetStream(); - virtual void stopInternetStream(); - virtual void pauseInternetStream(int pause); - virtual int isInternetStreamPlaying(); - virtual void setInternetStreamGain(F32 vol); - /*virtual*/ void initWind(); /*virtual*/ void cleanupWind(); @@ -83,15 +74,9 @@ class LLAudioEngine_FMOD : public LLAudioEngine protected: static signed char F_CALLBACKAPI callbackMetaData(char* name, char* value, void* userdata); - LLAudioStreamFMOD *mCurrentInternetStreamp; - int mInternetStreamChannel; - - std::list mDeadStreams; - //F32 mMinDistance[MAX_BUFFERS]; //F32 mMaxDistance[MAX_BUFFERS]; - S32 mFadeIn; bool mInited; // On Windows, userdata is the HWND of the application window. @@ -140,22 +125,5 @@ class LLAudioBufferFMOD : public LLAudioBuffer FSOUND_SAMPLE *mSamplep; }; -class LLAudioStreamFMOD -{ -public: - LLAudioStreamFMOD(const std::string& url); - int startStream(); - bool stopStream(); // Returns true if the stream was successfully stopped. - bool ready(); - - const std::string& getURL() { return mInternetStreamURL; } - - int getOpenState(); -protected: - FSOUND_STREAM* mInternetStream; - bool mReady; - - std::string mInternetStreamURL; -}; #endif // LL_AUDIOENGINE_FMOD_H diff --git a/linden/indra/llaudio/audioengine_openal.cpp b/linden/indra/llaudio/llaudioengine_openal.cpp similarity index 93% rename from linden/indra/llaudio/audioengine_openal.cpp rename to linden/indra/llaudio/llaudioengine_openal.cpp index 84305f0f7..93bc42b70 100644 --- a/linden/indra/llaudio/audioengine_openal.cpp +++ b/linden/indra/llaudio/llaudioengine_openal.cpp @@ -34,10 +34,12 @@ #include "linden_common.h" #include "lldir.h" -#include "audioengine_openal.h" -#include "listener_openal.h" +#include "llaudioengine_openal.h" +#include "lllistener_openal.h" +static const float WIND_BUFFER_SIZE_SEC = 0.05f; // 1/20th sec + LLAudioEngine_OpenAL::LLAudioEngine_OpenAL() : mWindGen(NULL), @@ -55,41 +57,15 @@ LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL() { } -static ALboolean alutInitHelp(const char **errorstring) -{ - ALboolean result = AL_FALSE; - ALenum err = AL_NO_ERROR; -#if LL_WINDOWS - __try { - result = alutInit(NULL, NULL); - err = alutGetError(); - alGetError(); // hit loading of wrap_oal.dll - if(!result) *errorstring = alutGetErrorString(err); - } __except( EXCEPTION_EXECUTE_HANDLER ) { - *errorstring = "[Exception]"; - result = AL_FALSE; - } - return result; -#else - result = alutInit(NULL, NULL); - if(!result) { - err = alutGetError(); - *errorstring = alutGetErrorString(err); - } - return result; -#endif -} - // virtual bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata) { - const char *errorstring = "(null)"; mWindGen = NULL; LLAudioEngine::init(num_channels, userdata); - if(!alutInitHelp(&errorstring)) + if(!alutInit(NULL, NULL)) { - llwarns << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << errorstring << llendl; + llwarns << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << alutGetErrorString (alutGetError ()) << llendl; return false; } @@ -287,8 +263,6 @@ bool LLAudioChannelOpenAL::updateBuffer() mCurrentSourcep->isLoop() ? AL_TRUE : AL_FALSE); alSourcef(mALSource, AL_ROLLOFF_FACTOR, gAudiop->mListenerp->getRolloffFactor()); - alSourcef(mALSource, AL_REFERENCE_DISTANCE, - gAudiop->mListenerp->getDistanceFactor()); } return true; @@ -417,7 +391,7 @@ void LLAudioEngine_OpenAL::initWind() mWindGen = new LLWindGen; mWindBufFreq = mWindGen->getInputSamplingRate(); - mWindBufSamples = llceil(mWindBufFreq * 0.05f); // 1/20th sec - WIND_BUFFER_SIZE_SEC + mWindBufSamples = llceil(mWindBufFreq * WIND_BUFFER_SIZE_SEC); mWindBufBytes = mWindBufSamples * 2 /*stereo*/ * sizeof(WIND_SAMPLE_T); mWindBuf = new WIND_SAMPLE_T [mWindBufSamples * 2 /*stereo*/]; diff --git a/linden/indra/llaudio/audioengine_openal.h b/linden/indra/llaudio/llaudioengine_openal.h similarity index 97% rename from linden/indra/llaudio/audioengine_openal.h rename to linden/indra/llaudio/llaudioengine_openal.h index 8c8bfd93f..900bcb32c 100644 --- a/linden/indra/llaudio/audioengine_openal.h +++ b/linden/indra/llaudio/llaudioengine_openal.h @@ -36,10 +36,9 @@ #ifndef LL_AUDIOENGINE_OPENAL_H #define LL_AUDIOENGINE_OPENAL_H -#include "audioengine.h" -#include "listener_openal.h" -#include "windgen.h" - +#include "llaudioengine.h" +#include "lllistener_openal.h" +#include "llwindgen.h" class LLAudioEngine_OpenAL : public LLAudioEngine { diff --git a/linden/indra/llaudio/lllistener.cpp b/linden/indra/llaudio/lllistener.cpp new file mode 100644 index 000000000..846c6bccb --- /dev/null +++ b/linden/indra/llaudio/lllistener.cpp @@ -0,0 +1,142 @@ +/** + * @file listener.cpp + * @brief Implementation of LISTENER class abstracting the audio support + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lllistener.h" + +#define DEFAULT_AT 0.0f,0.0f,-1.0f +#define DEFAULT_UP 0.0f,1.0f,0.0f + +//----------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------- +LLListener::LLListener() +{ + init(); +} + +//----------------------------------------------------------------------- +LLListener::~LLListener() +{ +} + +//----------------------------------------------------------------------- +void LLListener::init(void) +{ + mPosition.zeroVec(); + mListenAt.setVec(DEFAULT_AT); + mListenUp.setVec(DEFAULT_UP); + mVelocity.zeroVec(); +} + +//----------------------------------------------------------------------- +void LLListener::translate(LLVector3 offset) +{ + mPosition += offset; +} + +//----------------------------------------------------------------------- +void LLListener::setPosition(LLVector3 pos) +{ + mPosition = pos; +} + +//----------------------------------------------------------------------- +LLVector3 LLListener::getPosition(void) +{ + return(mPosition); +} + +//----------------------------------------------------------------------- +LLVector3 LLListener::getAt(void) +{ + return(mListenAt); +} + +//----------------------------------------------------------------------- +LLVector3 LLListener::getUp(void) +{ + return(mListenUp); +} + +//----------------------------------------------------------------------- +void LLListener::setVelocity(LLVector3 vel) +{ + mVelocity = vel; +} + +//----------------------------------------------------------------------- +void LLListener::orient(LLVector3 up, LLVector3 at) +{ + mListenUp = up; + mListenAt = at; +} + +//----------------------------------------------------------------------- +void LLListener::set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at) +{ + mPosition = pos; + mVelocity = vel; + + setPosition(pos); + setVelocity(vel); + orient(up,at); +} + +//----------------------------------------------------------------------- +void LLListener::setDopplerFactor(F32 factor) +{ +} + +//----------------------------------------------------------------------- +F32 LLListener::getDopplerFactor() +{ + return (1.f); +} + +//----------------------------------------------------------------------- +void LLListener::setRolloffFactor(F32 factor) +{ +} + +//----------------------------------------------------------------------- +F32 LLListener::getRolloffFactor() +{ + return (1.f); +} + +//----------------------------------------------------------------------- +void LLListener::commitDeferredChanges() +{ +} + diff --git a/linden/indra/llaudio/lllistener.h b/linden/indra/llaudio/lllistener.h new file mode 100644 index 000000000..e94fbe853 --- /dev/null +++ b/linden/indra/llaudio/lllistener.h @@ -0,0 +1,78 @@ +/** + * @file listener.h + * @brief Description of LISTENER base class abstracting the audio support. + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LISTENER_H +#define LL_LISTENER_H + +#include "v3math.h" + +class LLListener +{ + private: + protected: + LLVector3 mPosition; + LLVector3 mVelocity; + LLVector3 mListenAt; + LLVector3 mListenUp; + + public: + + private: + protected: + public: + LLListener(); + virtual ~LLListener(); + virtual void init(); + + virtual void set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at); + + virtual void setPosition(LLVector3 pos); + virtual void setVelocity(LLVector3 vel); + + virtual void orient(LLVector3 up, LLVector3 at); + virtual void translate(LLVector3 offset); + + virtual void setDopplerFactor(F32 factor); + virtual void setRolloffFactor(F32 factor); + + virtual LLVector3 getPosition(); + virtual LLVector3 getAt(); + virtual LLVector3 getUp(); + + virtual F32 getDopplerFactor(); + virtual F32 getRolloffFactor(); + + virtual void commitDeferredChanges(); +}; + +#endif + diff --git a/linden/indra/llaudio/lllistener_ds3d.h b/linden/indra/llaudio/lllistener_ds3d.h new file mode 100644 index 000000000..1ff9c170c --- /dev/null +++ b/linden/indra/llaudio/lllistener_ds3d.h @@ -0,0 +1,74 @@ +/** + * @file listener_ds3d.h + * @brief Description of LISTENER class abstracting the audio support + * as a DirectSound 3D implementation (windows only) + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LISTENER_DS3D_H +#define LL_LISTENER_DS3D_H + +#include "lllistener.h" + +#include +#include +#include + +class LLListener_DS3D : public LLListener +{ + private: + protected: + IDirectSound3DListener8 *m3DListener; + public: + + private: + protected: + public: + LLListener_DS3D(); + virtual ~LLListener_DS3D(); + virtual void init(); + + virtual void setDS3DLPtr (IDirectSound3DListener8 *listener_p); + + virtual void translate(LLVector3 offset); + virtual void setPosition(LLVector3 pos); + virtual void setVelocity(LLVector3 vel); + virtual void orient(LLVector3 up, LLVector3 at); + + virtual void setDopplerFactor(F32 factor); + virtual F32 getDopplerFactor(); + virtual void setRolloffFactor(F32 factor); + virtual F32 getRolloffFactor(); + + virtual void commitDeferredChanges(); +}; + +#endif + + diff --git a/linden/indra/llaudio/lllistener_fmod.cpp b/linden/indra/llaudio/lllistener_fmod.cpp new file mode 100644 index 000000000..57ad461b0 --- /dev/null +++ b/linden/indra/llaudio/lllistener_fmod.cpp @@ -0,0 +1,131 @@ +/** + * @file listener_fmod.cpp + * @brief implementation of LISTENER class abstracting the audio + * support as a FMOD 3D implementation (windows only) + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llaudioengine.h" +#include "lllistener_fmod.h" +#include "fmod.h" + +//----------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------- +LLListener_FMOD::LLListener_FMOD() +{ + init(); +} + +//----------------------------------------------------------------------- +LLListener_FMOD::~LLListener_FMOD() +{ +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::init(void) +{ + // do inherited + LLListener::init(); + mDopplerFactor = 1.0f; + mRolloffFactor = 1.0f; +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::translate(LLVector3 offset) +{ + LLListener::translate(offset); + + FSOUND_3D_Listener_SetAttributes(mPosition.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::setPosition(LLVector3 pos) +{ + LLListener::setPosition(pos); + + FSOUND_3D_Listener_SetAttributes(pos.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::setVelocity(LLVector3 vel) +{ + LLListener::setVelocity(vel); + + FSOUND_3D_Listener_SetAttributes(NULL, vel.mV, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::orient(LLVector3 up, LLVector3 at) +{ + LLListener::orient(up, at); + + // Welcome to the transition between right and left + // (coordinate systems, that is) + // Leaving the at vector alone results in a L/R reversal + // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed + at = -at; + + FSOUND_3D_Listener_SetAttributes(NULL, NULL, at.mV[0],at.mV[1],at.mV[2], up.mV[0],up.mV[1],up.mV[2]); +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::commitDeferredChanges() +{ + FSOUND_Update(); +} + + +void LLListener_FMOD::setRolloffFactor(F32 factor) +{ + mRolloffFactor = factor; + FSOUND_3D_SetRolloffFactor(factor); +} + + +F32 LLListener_FMOD::getRolloffFactor() +{ + return mRolloffFactor; +} + + +void LLListener_FMOD::setDopplerFactor(F32 factor) +{ + mDopplerFactor = factor; + FSOUND_3D_SetDopplerFactor(factor); +} + + +F32 LLListener_FMOD::getDopplerFactor() +{ + return mDopplerFactor; +} + + diff --git a/linden/indra/llaudio/lllistener_fmod.h b/linden/indra/llaudio/lllistener_fmod.h new file mode 100644 index 000000000..5a48ec8b6 --- /dev/null +++ b/linden/indra/llaudio/lllistener_fmod.h @@ -0,0 +1,64 @@ +/** + * @file listener_fmod.h + * @brief Description of LISTENER class abstracting the audio support + * as an FMOD 3D implementation (windows and Linux) + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LISTENER_FMOD_H +#define LL_LISTENER_FMOD_H + +#include "lllistener.h" + +class LLListener_FMOD : public LLListener +{ + public: + LLListener_FMOD(); + virtual ~LLListener_FMOD(); + virtual void init(); + + virtual void translate(LLVector3 offset); + virtual void setPosition(LLVector3 pos); + virtual void setVelocity(LLVector3 vel); + virtual void orient(LLVector3 up, LLVector3 at); + virtual void commitDeferredChanges(); + + virtual void setDopplerFactor(F32 factor); + virtual F32 getDopplerFactor(); + virtual void setRolloffFactor(F32 factor); + virtual F32 getRolloffFactor(); + + protected: + F32 mDopplerFactor; + F32 mRolloffFactor; +}; + +#endif + + diff --git a/linden/indra/llaudio/listener_openal.cpp b/linden/indra/llaudio/lllistener_openal.cpp similarity index 93% rename from linden/indra/llaudio/listener_openal.cpp rename to linden/indra/llaudio/lllistener_openal.cpp index d0ef9b2f5..a96ebd5db 100644 --- a/linden/indra/llaudio/listener_openal.cpp +++ b/linden/indra/llaudio/lllistener_openal.cpp @@ -32,9 +32,9 @@ */ #include "linden_common.h" -#include "audioengine.h" +#include "llaudioengine.h" -#include "listener_openal.h" +#include "lllistener_openal.h" LLListener_OpenAL::LLListener_OpenAL() { @@ -114,12 +114,3 @@ F32 LLListener_OpenAL::getRolloffFactor() } -void LLListener_OpenAL::setDistanceFactor(F32 factor) -{ - mDistanceFactor = factor; -} - -F32 LLListener_OpenAL::getDistanceFactor() -{ - return mDistanceFactor; -} diff --git a/linden/indra/llaudio/listener_openal.h b/linden/indra/llaudio/lllistener_openal.h similarity index 93% rename from linden/indra/llaudio/listener_openal.h rename to linden/indra/llaudio/lllistener_openal.h index 2b79ada9c..0dfeea5c9 100644 --- a/linden/indra/llaudio/listener_openal.h +++ b/linden/indra/llaudio/lllistener_openal.h @@ -34,10 +34,9 @@ #ifndef LL_LISTENER_OPENAL_H #define LL_LISTENER_OPENAL_H -#include "listener.h" +#include "lllistener.h" - -//#include "AL/al.h" +#include "AL/al.h" #include "AL/alut.h" class LLListener_OpenAL : public LLListener @@ -54,13 +53,10 @@ class LLListener_OpenAL : public LLListener virtual void setDopplerFactor(F32 factor); virtual F32 getDopplerFactor(); - virtual void setDistanceFactor(F32 factor); - virtual F32 getDistanceFactor(); virtual void setRolloffFactor(F32 factor); virtual F32 getRolloffFactor(); protected: - F32 mDistanceFactor; F32 mRolloffFactor; }; diff --git a/linden/indra/llaudio/llstreamingaudio.h b/linden/indra/llaudio/llstreamingaudio.h new file mode 100644 index 000000000..aa89e6a17 --- /dev/null +++ b/linden/indra/llaudio/llstreamingaudio.h @@ -0,0 +1,56 @@ +/** + * @file streamingaudio.h + * @author Tofu Linden + * @brief Definition of LLStreamingAudioInterface base class abstracting the streaming audio interface + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_STREAMINGAUDIO_H +#define LL_STREAMINGAUDIO_H + +#include "stdtypes.h" // from llcommon + +// Entirely abstract. Based exactly on the historic API. +class LLStreamingAudioInterface +{ + public: + virtual ~LLStreamingAudioInterface() {} + + virtual void start(const std::string& url) = 0; + virtual void stop() = 0; + virtual void pause(int pause) = 0; + virtual void update() = 0; + virtual int isPlaying() = 0; + // use a value from 0.0 to 1.0, inclusive + virtual void setGain(F32 vol) = 0; + virtual F32 getGain() = 0; + virtual std::string getURL() = 0; +}; + +#endif // LL_STREAMINGAUDIO_H diff --git a/linden/indra/llaudio/llstreamingaudio_fmod.cpp b/linden/indra/llaudio/llstreamingaudio_fmod.cpp new file mode 100644 index 000000000..a71a87203 --- /dev/null +++ b/linden/indra/llaudio/llstreamingaudio_fmod.cpp @@ -0,0 +1,362 @@ +/** + * @file streamingaudio_fmod.cpp + * @brief LLStreamingAudio_FMOD implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llmath.h" + +#include "fmod.h" +#include "fmod_errors.h" + +#include "llstreamingaudio_fmod.h" + + +class LLAudioStreamManagerFMOD +{ +public: + LLAudioStreamManagerFMOD(const std::string& url); + int startStream(); + bool stopStream(); // Returns true if the stream was successfully stopped. + bool ready(); + + const std::string& getURL() { return mInternetStreamURL; } + + int getOpenState(); +protected: + FSOUND_STREAM* mInternetStream; + bool mReady; + + std::string mInternetStreamURL; +}; + + + +//--------------------------------------------------------------------------- +// Internet Streaming +//--------------------------------------------------------------------------- +LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() : + mCurrentInternetStreamp(NULL), + mFMODInternetStreamChannel(-1), + mGain(1.0f) +{ + // Number of milliseconds of audio to buffer for the audio card. + // Must be larger than the usual Second Life frame stutter time. + FSOUND_Stream_SetBufferSize(200); + + // Here's where we set the size of the network buffer and some buffering + // parameters. In this case we want a network buffer of 16k, we want it + // to prebuffer 40% of that when we first connect, and we want it + // to rebuffer 80% of that whenever we encounter a buffer underrun. + + // Leave the net buffer properties at the default. + //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80); +} + + +LLStreamingAudio_FMOD::~LLStreamingAudio_FMOD() +{ + // nothing interesting/safe to do. +} + + +void LLStreamingAudio_FMOD::start(const std::string& url) +{ + //if (!mInited) + //{ + // llwarns << "startInternetStream before audio initialized" << llendl; + // return; + //} + + // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL + stop(); + + if (!url.empty()) + { + llinfos << "Starting internet stream: " << url << llendl; + mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url); + mURL = url; + } + else + { + llinfos << "Set internet stream to null" << llendl; + mURL.clear(); + } +} + + +void LLStreamingAudio_FMOD::update() +{ + // Kill dead internet streams, if possible + std::list::iterator iter; + for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) + { + LLAudioStreamManagerFMOD *streamp = *iter; + if (streamp->stopStream()) + { + llinfos << "Closed dead stream" << llendl; + delete streamp; + mDeadStreams.erase(iter++); + } + else + { + iter++; + } + } + + // Don't do anything if there are no streams playing + if (!mCurrentInternetStreamp) + { + return; + } + + int open_state = mCurrentInternetStreamp->getOpenState(); + + if (!open_state) + { + // Stream is live + + // start the stream if it's ready + if (mFMODInternetStreamChannel < 0) + { + mFMODInternetStreamChannel = mCurrentInternetStreamp->startStream(); + + if (mFMODInternetStreamChannel != -1) + { + // Reset volume to previously set volume + setGain(getGain()); + FSOUND_SetPaused(mFMODInternetStreamChannel, false); + } + } + } + + switch(open_state) + { + default: + case 0: + // success + break; + case -1: + // stream handle is invalid + llwarns << "InternetStream - invalid handle" << llendl; + stop(); + return; + case -2: + // opening + break; + case -3: + // failed to open, file not found, perhaps + llwarns << "InternetSteam - failed to open" << llendl; + stop(); + return; + case -4: + // connecting + break; + case -5: + // buffering + break; + } + +} + +void LLStreamingAudio_FMOD::stop() +{ + if (mFMODInternetStreamChannel != -1) + { + FSOUND_SetPaused(mFMODInternetStreamChannel, true); + FSOUND_SetPriority(mFMODInternetStreamChannel, 0); + mFMODInternetStreamChannel = -1; + } + + if (mCurrentInternetStreamp) + { + llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl; + if (mCurrentInternetStreamp->stopStream()) + { + delete mCurrentInternetStreamp; + } + else + { + llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl; + mDeadStreams.push_back(mCurrentInternetStreamp); + } + mCurrentInternetStreamp = NULL; + //mURL.clear(); + } +} + +void LLStreamingAudio_FMOD::pause(int pauseopt) +{ + if (pauseopt < 0) + { + pauseopt = mCurrentInternetStreamp ? 1 : 0; + } + + if (pauseopt) + { + if (mCurrentInternetStreamp) + { + stop(); + } + } + else + { + start(getURL()); + } +} + + +// A stream is "playing" if it has been requested to start. That +// doesn't necessarily mean audio is coming out of the speakers. +int LLStreamingAudio_FMOD::isPlaying() +{ + if (mCurrentInternetStreamp) + { + return 1; // Active and playing + } + else if (!mURL.empty()) + { + return 2; // "Paused" + } + else + { + return 0; + } +} + + +F32 LLStreamingAudio_FMOD::getGain() +{ + return mGain; +} + + +std::string LLStreamingAudio_FMOD::getURL() +{ + return mURL; +} + + +void LLStreamingAudio_FMOD::setGain(F32 vol) +{ + mGain = vol; + + if (mFMODInternetStreamChannel != -1) + { + vol = llclamp(vol, 0.f, 1.f); + int vol_int = llround(vol * 255.f); + FSOUND_SetVolumeAbsolute(mFMODInternetStreamChannel, vol_int); + } +} + + +/////////////////////////////////////////////////////// +// manager of possibly-multiple internet audio streams + +LLAudioStreamManagerFMOD::LLAudioStreamManagerFMOD(const std::string& url) : + mInternetStream(NULL), + mReady(false) +{ + mInternetStreamURL = url; + mInternetStream = FSOUND_Stream_Open(url.c_str(), FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); + if (!mInternetStream) + { + llwarns << "Couldn't open fmod stream, error " + << FMOD_ErrorString(FSOUND_GetError()) + << llendl; + mReady = false; + return; + } + + mReady = true; +} + +int LLAudioStreamManagerFMOD::startStream() +{ + // We need a live and opened stream before we try and play it. + if (!mInternetStream || getOpenState()) + { + llwarns << "No internet stream to start playing!" << llendl; + return -1; + } + + // Make sure the stream is set to 2D mode. + FSOUND_Stream_SetMode(mInternetStream, FSOUND_2D); + + return FSOUND_Stream_PlayEx(FSOUND_FREE, mInternetStream, NULL, true); +} + +bool LLAudioStreamManagerFMOD::stopStream() +{ + if (mInternetStream) + { + int read_percent = 0; + int status = 0; + int bitrate = 0; + unsigned int flags = 0x0; + FSOUND_Stream_Net_GetStatus(mInternetStream, &status, &read_percent, &bitrate, &flags); + + bool close = true; + switch (status) + { + case FSOUND_STREAM_NET_CONNECTING: + close = false; + break; + case FSOUND_STREAM_NET_NOTCONNECTED: + case FSOUND_STREAM_NET_BUFFERING: + case FSOUND_STREAM_NET_READY: + case FSOUND_STREAM_NET_ERROR: + default: + close = true; + } + + if (close) + { + FSOUND_Stream_Close(mInternetStream); + mInternetStream = NULL; + return true; + } + else + { + return false; + } + } + else + { + return true; + } +} + +int LLAudioStreamManagerFMOD::getOpenState() +{ + int open_state = FSOUND_Stream_GetOpenState(mInternetStream); + return open_state; +} diff --git a/linden/indra/llaudio/llstreamingaudio_fmod.h b/linden/indra/llaudio/llstreamingaudio_fmod.h new file mode 100644 index 000000000..968ab53a0 --- /dev/null +++ b/linden/indra/llaudio/llstreamingaudio_fmod.h @@ -0,0 +1,68 @@ +/** + * @file streamingaudio_fmod.h + * @author Tofu Linden + * @brief Definition of LLStreamingAudio_FMOD implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_STREAMINGAUDIO_FMOD_H +#define LL_STREAMINGAUDIO_FMOD_H + +#include "stdtypes.h" // from llcommon + +#include "llstreamingaudio.h" + +class LLAudioStreamManagerFMOD; + +class LLStreamingAudio_FMOD : public LLStreamingAudioInterface +{ + public: + LLStreamingAudio_FMOD(); + /*virtual*/ ~LLStreamingAudio_FMOD(); + + /*virtual*/ void start(const std::string& url); + /*virtual*/ void stop(); + /*virtual*/ void pause(int pause); + /*virtual*/ void update(); + /*virtual*/ int isPlaying(); + /*virtual*/ void setGain(F32 vol); + /*virtual*/ F32 getGain(); + /*virtual*/ std::string getURL(); + +private: + LLAudioStreamManagerFMOD *mCurrentInternetStreamp; + int mFMODInternetStreamChannel; + std::list mDeadStreams; + + std::string mURL; + F32 mGain; +}; + + +#endif // LL_STREAMINGAUDIO_FMOD_H diff --git a/linden/indra/llaudio/vorbisdecode.cpp b/linden/indra/llaudio/llvorbisdecode.cpp similarity index 100% rename from linden/indra/llaudio/vorbisdecode.cpp rename to linden/indra/llaudio/llvorbisdecode.cpp diff --git a/linden/indra/llaudio/vorbisdecode.h b/linden/indra/llaudio/llvorbisdecode.h similarity index 100% rename from linden/indra/llaudio/vorbisdecode.h rename to linden/indra/llaudio/llvorbisdecode.h diff --git a/linden/indra/llaudio/llvorbisencode.cpp b/linden/indra/llaudio/llvorbisencode.cpp new file mode 100644 index 000000000..a24394da1 --- /dev/null +++ b/linden/indra/llaudio/llvorbisencode.cpp @@ -0,0 +1,505 @@ +/** + * @file vorbisencode.cpp + * @brief Vorbis encoding routine routine for Indra. + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "vorbis/vorbisenc.h" + +#include "llvorbisencode.h" +#include "llerror.h" +#include "llrand.h" +#include "llmath.h" +#include "llapr.h" + +//#if LL_DARWIN +// MBW -- XXX -- Getting rid of SecondLifeVorbis for now -- no fmod means no name collisions. +#if 0 +#include "VorbisFramework.h" + +#define vorbis_analysis mac_vorbis_analysis +#define vorbis_analysis_headerout mac_vorbis_analysis_headerout +#define vorbis_analysis_init mac_vorbis_analysis_init +#define vorbis_encode_ctl mac_vorbis_encode_ctl +#define vorbis_encode_setup_init mac_vorbis_encode_setup_init +#define vorbis_encode_setup_managed mac_vorbis_encode_setup_managed + +#define vorbis_info_init mac_vorbis_info_init +#define vorbis_info_clear mac_vorbis_info_clear +#define vorbis_comment_init mac_vorbis_comment_init +#define vorbis_comment_clear mac_vorbis_comment_clear +#define vorbis_block_init mac_vorbis_block_init +#define vorbis_block_clear mac_vorbis_block_clear +#define vorbis_dsp_clear mac_vorbis_dsp_clear +#define vorbis_analysis_buffer mac_vorbis_analysis_buffer +#define vorbis_analysis_wrote mac_vorbis_analysis_wrote +#define vorbis_analysis_blockout mac_vorbis_analysis_blockout + +#define ogg_stream_packetin mac_ogg_stream_packetin +#define ogg_stream_init mac_ogg_stream_init +#define ogg_stream_flush mac_ogg_stream_flush +#define ogg_stream_pageout mac_ogg_stream_pageout +#define ogg_page_eos mac_ogg_page_eos +#define ogg_stream_clear mac_ogg_stream_clear + +#endif + +S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& error_msg) +{ + U16 num_channels = 0; + U32 sample_rate = 0; + U32 bits_per_sample = 0; + U32 physical_file_size = 0; + U32 chunk_length = 0; + U32 raw_data_length = 0; + U32 bytes_per_sec = 0; + BOOL uncompressed_pcm = FALSE; + + unsigned char wav_header[44]; /*Flawfinder: ignore*/ + + error_msg.clear(); + + //******************************** + LLAPRFile infile ; + infile.open(in_fname,LL_APR_RB, LLAPRFile::global); + //******************************** + if (!infile.getFileHandle()) + { + error_msg = "CannotUploadSoundFile"; + return(LLVORBISENC_SOURCE_OPEN_ERR); + } + + infile.read(wav_header, 44); + physical_file_size = infile.seek(APR_END,0); + + if (strncmp((char *)&(wav_header[0]),"RIFF",4)) + { + error_msg = "SoundFileNotRIFF"; + return(LLVORBISENC_WAV_FORMAT_ERR); + } + + if (strncmp((char *)&(wav_header[8]),"WAVE",4)) + { + error_msg = "SoundFileNotRIFF"; + return(LLVORBISENC_WAV_FORMAT_ERR); + } + + // parse the chunks + + U32 file_pos = 12; // start at the first chunk (usually fmt but not always) + + while ((file_pos + 8)< physical_file_size) + { + infile.seek(APR_SET,file_pos); + infile.read(wav_header, 44); + + chunk_length = ((U32) wav_header[7] << 24) + + ((U32) wav_header[6] << 16) + + ((U32) wav_header[5] << 8) + + wav_header[4]; + +// llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl; + + if (!(strncmp((char *)&(wav_header[0]),"fmt ",4))) + { + if ((wav_header[8] == 0x01) && (wav_header[9] == 0x00)) + { + uncompressed_pcm = TRUE; + } + num_channels = ((U16) wav_header[11] << 8) + wav_header[10]; + sample_rate = ((U32) wav_header[15] << 24) + + ((U32) wav_header[14] << 16) + + ((U32) wav_header[13] << 8) + + wav_header[12]; + bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22]; + bytes_per_sec = ((U32) wav_header[19] << 24) + + ((U32) wav_header[18] << 16) + + ((U32) wav_header[17] << 8) + + wav_header[16]; + } + else if (!(strncmp((char *)&(wav_header[0]),"data",4))) + { + raw_data_length = chunk_length; + } + file_pos += (chunk_length + 8); + chunk_length = 0; + } + //**************** + infile.close(); + //**************** + + if (!uncompressed_pcm) + { + error_msg = "SoundFileNotPCM"; + return(LLVORBISENC_PCM_FORMAT_ERR); + } + + if ((num_channels < 1) || (num_channels > LLVORBIS_CLIP_MAX_CHANNELS)) + { + error_msg = "SoundFileInvalidChannelCount"; + return(LLVORBISENC_MULTICHANNEL_ERR); + } + + if (sample_rate != LLVORBIS_CLIP_SAMPLE_RATE) + { + error_msg = "SoundFileInvalidSampleRate"; + return(LLVORBISENC_UNSUPPORTED_SAMPLE_RATE); + } + + if ((bits_per_sample != 16) && (bits_per_sample != 8)) + { + error_msg = "SoundFileInvalidWordSize"; + return(LLVORBISENC_UNSUPPORTED_WORD_SIZE); + } + + if (!raw_data_length) + { + error_msg = "SoundFileInvalidHeader"; + return(LLVORBISENC_CLIP_TOO_LONG); + } + + F32 clip_length = (F32)raw_data_length/(F32)bytes_per_sec; + + if (clip_length > LLVORBIS_CLIP_MAX_TIME) + { + error_msg = "SoundFileInvalidTooLong"; + return(LLVORBISENC_CLIP_TOO_LONG); + } + + return(LLVORBISENC_NOERR); +} + +S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname) +{ +#define READ_BUFFER 1024 + unsigned char readbuffer[READ_BUFFER*4+44]; /* out of the data segment, not the stack */ /*Flawfinder: ignore*/ + + ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ + ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ + ogg_packet op; /* one raw packet of data for decode */ + + vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ + vorbis_comment vc; /* struct that stores all the user comments */ + + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + + int eos=0; + int result; + + U16 num_channels = 0; + U32 sample_rate = 0; + U32 bits_per_sample = 0; + + S32 format_error = 0; + std::string error_msg; + if ((format_error = check_for_invalid_wav_formats(in_fname, error_msg))) + { + llwarns << error_msg << ": " << in_fname << llendl; + return(format_error); + } + +#if 1 + unsigned char wav_header[44]; /*Flawfinder: ignore*/ + + S32 data_left = 0; + + LLAPRFile infile ; + infile.open(in_fname,LL_APR_RB, LLAPRFile::global); + if (!infile.getFileHandle()) + { + llwarns << "Couldn't open temporary ogg file for writing: " << in_fname + << llendl; + return(LLVORBISENC_SOURCE_OPEN_ERR); + } + + LLAPRFile outfile ; + outfile.open(out_fname,LL_APR_WPB, LLAPRFile::global); + if (!outfile.getFileHandle()) + { + llwarns << "Couldn't open upload sound file for reading: " << in_fname + << llendl; + return(LLVORBISENC_DEST_OPEN_ERR); + } + + // parse the chunks + U32 chunk_length = 0; + U32 file_pos = 12; // start at the first chunk (usually fmt but not always) + + while (infile.eof() != APR_EOF) + { + infile.seek(APR_SET,file_pos); + infile.read(wav_header, 44); + + chunk_length = ((U32) wav_header[7] << 24) + + ((U32) wav_header[6] << 16) + + ((U32) wav_header[5] << 8) + + wav_header[4]; + +// llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl; + + if (!(strncmp((char *)&(wav_header[0]),"fmt ",4))) + { + num_channels = ((U16) wav_header[11] << 8) + wav_header[10]; + sample_rate = ((U32) wav_header[15] << 24) + + ((U32) wav_header[14] << 16) + + ((U32) wav_header[13] << 8) + + wav_header[12]; + bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22]; + } + else if (!(strncmp((char *)&(wav_header[0]),"data",4))) + { + infile.seek(APR_SET,file_pos+8); + // leave the file pointer at the beginning of the data chunk data + data_left = chunk_length; + break; + } + file_pos += (chunk_length + 8); + chunk_length = 0; + } + + + /********** Encode setup ************/ + + /* choose an encoding mode */ + /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */ + vorbis_info_init(&vi); + + // always encode to mono + + // SL-52913 & SL-53779 determined this quality level to be our 'good + // enough' general-purpose quality level with a nice low bitrate. + // Equivalent to oggenc -q0.5 + F32 quality = 0.05f; +// quality = (bitrate==128000 ? 0.4f : 0.1); + +// if (vorbis_encode_init(&vi, /* num_channels */ 1 ,sample_rate, -1, bitrate, -1)) + if (vorbis_encode_init_vbr(&vi, /* num_channels */ 1 ,sample_rate, quality)) +// if (vorbis_encode_setup_managed(&vi,1,sample_rate,-1,bitrate,-1) || +// vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE_AVG,NULL) || +// vorbis_encode_setup_init(&vi)) + { + llwarns << "unable to initialize vorbis codec at quality " << quality << llendl; + // llwarns << "unable to initialize vorbis codec at bitrate " << bitrate << llendl; + return(LLVORBISENC_DEST_OPEN_ERR); + } + + /* add a comment */ + vorbis_comment_init(&vc); +// vorbis_comment_add(&vc,"Linden"); + + /* set up the analysis state and auxiliary encoding storage */ + vorbis_analysis_init(&vd,&vi); + vorbis_block_init(&vd,&vb); + + /* set up our packet->stream encoder */ + /* pick a random serial number; that way we can more likely build + chained streams just by concatenation */ + ogg_stream_init(&os, ll_rand()); + + /* Vorbis streams begin with three headers; the initial header (with + most of the codec setup parameters) which is mandated by the Ogg + bitstream spec. The second header holds any comment fields. The + third header holds the bitstream codebook. We merely need to + make the headers, then pass them to libvorbis one at a time; + libvorbis handles the additional Ogg bitstream constraints */ + + { + ogg_packet header; + ogg_packet header_comm; + ogg_packet header_code; + + vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code); + ogg_stream_packetin(&os,&header); /* automatically placed in its own + page */ + ogg_stream_packetin(&os,&header_comm); + ogg_stream_packetin(&os,&header_code); + + /* We don't have to write out here, but doing so makes streaming + * much easier, so we do, flushing ALL pages. This ensures the actual + * audio data will start on a new page + */ + while(!eos){ + int result=ogg_stream_flush(&os,&og); + if(result==0)break; + outfile.write(og.header, og.header_len); + outfile.write(og.body, og.body_len); + } + + } + + + while(!eos) + { + long bytes_per_sample = bits_per_sample/8; + + long bytes=(long)infile.read(readbuffer,llclamp((S32)(READ_BUFFER*num_channels*bytes_per_sample),0,data_left)); /* stereo hardwired here */ + + if (bytes==0) + { + /* end of file. this can be done implicitly in the mainline, + but it's easier to see here in non-clever fashion. + Tell the library we're at end of stream so that it can handle + the last frame and mark end of stream in the output properly */ + + vorbis_analysis_wrote(&vd,0); +// eos = 1; + + } + else + { + long i; + long samples; + int temp; + + data_left -= bytes; + /* data to encode */ + + /* expose the buffer to submit data */ + float **buffer=vorbis_analysis_buffer(&vd,READ_BUFFER); + + i = 0; + samples = bytes / (num_channels * bytes_per_sample); + + if (num_channels == 2) + { + if (bytes_per_sample == 2) + { + /* uninterleave samples */ + for(i=0; i. + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 04/04/2010 + * - Initial version, written by Aleric Inglewood @ SL + * + * 10/11/2010 + * - Changed filename, class names and license to a more + * company-neutral format. + * - Added APR_HAS_THREADS #if's to allow creation and destruction + * of subpools by threads other than the parent pool owner. + */ + +#include "linden_common.h" + +#include "llerror.h" +#include "aiaprpool.h" +#include "llthread.h" + +// Create a subpool from parent. +void AIAPRPool::create(AIAPRPool& parent) +{ + llassert(!mPool); // Must be non-initialized. + mParent = &parent; + if (!mParent) // Using the default parameter? + { + // By default use the root pool of the current thread. + mParent = &AIThreadLocalData::tldata().mRootPool; + } + llassert(mParent->mPool); // Parent must be initialized. +#if APR_HAS_THREADS + // As per the documentation of APR (ie http://apr.apache.org/docs/apr/1.4/apr__pools_8h.html): + // + // Note that most operations on pools are not thread-safe: a single pool should only be + // accessed by a single thread at any given time. The one exception to this rule is creating + // a subpool of a given pool: one or more threads can safely create subpools at the same + // time that another thread accesses the parent pool. + // + // In other words, it's safe for any thread to create a (sub)pool, independent of who + // owns the parent pool. + mOwner = apr_os_thread_current(); +#else + mOwner = mParent->mOwner; + llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); +#endif + apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, mParent->mPool); + llassert_always(apr_pool_create_status == APR_SUCCESS); + llassert(mPool); // Initialized. + apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null); +} + +// Destroy the (sub)pool, if any. +void AIAPRPool::destroy(void) +{ + // Only do anything if we are not already (being) destroyed. + if (mPool) + { +#if !APR_HAS_THREADS + // If we are a root pool, then every thread may destruct us: in that case + // we have to assume that no other thread will use this pool concurrently, + // of course. Otherwise, if we are a subpool, only the thread that owns + // the parent may destruct us, since that is the pool that is still alive, + // possibly being used by others and being altered here. + llassert(!mParent || apr_os_thread_equal(mParent->mOwner, apr_os_thread_current())); +#endif + apr_pool_t* pool = mPool; + mPool = NULL; // Mark that we are BEING destructed. + apr_pool_cleanup_kill(pool, this, &s_plain_cleanup); + apr_pool_destroy(pool); + } +} + +bool AIAPRPool::parent_is_being_destructed(void) +{ + return mParent && (!mParent->mPool || mParent->parent_is_being_destructed()); +} + +AIAPRInitialization::AIAPRInitialization(void) +{ + static bool apr_initialized = false; + + if (!apr_initialized) + { + apr_initialize(); + } + + apr_initialized = true; +} + +bool AIAPRRootPool::sCountInitialized = false; +apr_uint32_t volatile AIAPRRootPool::sCount; + +extern apr_thread_mutex_t* gLogMutexp; +extern apr_thread_mutex_t* gCallStacksLogMutexp; + +AIAPRRootPool::AIAPRRootPool(void) : AIAPRInitialization(), AIAPRPool(0) +{ + // sCountInitialized don't need locking because when we get here there is still only a single thread. + if (!sCountInitialized) + { + // Initialize the logging mutex + apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool); + apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool); + + apr_status_t status = apr_atomic_init(mPool); + llassert_always(status == APR_SUCCESS); + apr_atomic_set32(&sCount, 1); // Set to 1 to account for the global root pool. + sCountInitialized = true; + + // Initialize thread-local APR pool support. + // Because this recursively calls AIAPRRootPool::AIAPRRootPool(void) + // it must be done last, so that sCount is already initialized. + AIThreadLocalData::init(); + } + apr_atomic_inc32(&sCount); +} + +AIAPRRootPool::~AIAPRRootPool() +{ + if (!apr_atomic_dec32(&sCount)) + { + // The last pool was destructed. Cleanup remainder of APR. + LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL; + + if (gLogMutexp) + { + // Clean up the logging mutex + + // All other threads NEED to be done before we clean up APR, so this is okay. + apr_thread_mutex_destroy(gLogMutexp); + gLogMutexp = NULL; + } + if (gCallStacksLogMutexp) + { + // Clean up the logging mutex + + // All other threads NEED to be done before we clean up APR, so this is okay. + apr_thread_mutex_destroy(gCallStacksLogMutexp); + gCallStacksLogMutexp = NULL; + } + + // Must destroy ALL, and therefore this last AIAPRRootPool, before terminating APR. + static_cast(this)->destroy(); + + apr_terminate(); + } +} + +//static +AIAPRRootPool& AIAPRRootPool::get(void) +{ + static AIAPRRootPool global_APRpool(0); // This is what used to be gAPRPoolp. + return global_APRpool; +} + +void AIVolatileAPRPool::clearVolatileAPRPool() +{ + llassert_always(mNumActiveRef > 0); + if (--mNumActiveRef == 0) + { + if (isOld()) + { + destroy(); + mNumTotalRef = 0 ; + } + else + { + // This does not actually free the memory, + // it just allows the pool to re-use this memory for the next allocation. + clear(); + } + } + + // Paranoia check if the pool is jammed. + llassert(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ; +} diff --git a/linden/indra/llcommon/aiaprpool.h b/linden/indra/llcommon/aiaprpool.h new file mode 100644 index 000000000..ac523a9b9 --- /dev/null +++ b/linden/indra/llcommon/aiaprpool.h @@ -0,0 +1,240 @@ +/** + * @file aiaprpool.h + * @brief Implementation of AIAPRPool. + * + * Copyright (c) 2010, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 04/04/2010 + * - Initial version, written by Aleric Inglewood @ SL + * + * 10/11/2010 + * - Changed filename, class names and license to a more + * company-neutral format. + * - Added APR_HAS_THREADS #if's to allow creation and destruction + * of subpools by threads other than the parent pool owner. + */ + +#ifndef AIAPRPOOL_H +#define AIAPRPOOL_H + +#ifdef LL_WINDOWS +//#include +# define WIN32_LEAN_AND_MEAN +# include // Needed before including apr_portable.h +#endif + +#include "apr_portable.h" +#include "apr_pools.h" +#include "llerror.h" + +extern void ll_init_apr(); + +/** + * @brief A wrapper around the APR memory pool API. + * + * Usage of this class should be restricted to passing it to libapr-1 function calls that need it. + * + */ +class LL_COMMON_API AIAPRPool +{ +protected: + apr_pool_t* mPool; //!< Pointer to the underlaying pool. NULL if not initialized. + AIAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero. + apr_os_thread_t mOwner; //!< The thread that owns this memory pool. Only valid when mPool is non-zero. + +public: + //! Construct an uninitialized (destructed) pool. + AIAPRPool(void) : mPool(NULL) { } + + //! Construct a subpool from an existing pool. + // This is not a copy-constructor, this class doesn't have one! + AIAPRPool(AIAPRPool& parent) : mPool(NULL) { create(parent); } + + //! Destruct the memory pool (free all of it's subpools and allocated memory). + ~AIAPRPool() { destroy(); } + +protected: + // Create a pool that is allocated from the Operating System. Only used by AIAPRRootPool. + AIAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current()) + { + apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, NULL); + llassert_always(apr_pool_create_status == APR_SUCCESS); + llassert(mPool); + apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null); + } + +public: + //! Create a subpool from parent. May only be called for an uninitialized/destroyed pool. + // The default parameter causes the root pool of the current thread to be used. + void create(AIAPRPool& parent = *static_cast(NULL)); + + //! Destroy the (sub)pool, if any. + void destroy(void); + + // Use some safebool idiom (http://www.artima.com/cppsource/safebool.html) rather than operator bool. + typedef apr_pool_t* const AIAPRPool::* const bool_type; + //! Return true if the pool is initialized. + operator bool_type() const { return mPool ? &AIAPRPool::mPool : 0; } + + // Painful, but we have to either provide access to this, or wrap + // every APR function call that needs a apr_pool_t* to be passed. + // NEVER destroy a pool that is returned by this function! + apr_pool_t* operator()(void) const + { + llassert(mPool); + llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + return mPool; + } + + // Free all memory without destructing the pool. + void clear(void) + { + llassert(mPool); + llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + apr_pool_clear(mPool); + } + +// These methods would make this class 'complete' (as wrapper around the libapr +// pool functions), but we don't use memory pools in the viewer (only when +// we are forced to pass one to a libapr call), so don't define them in order +// not to encourage people to use them. +#if 0 + void* palloc(size_t size) + { + llassert(mPool); + llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + return apr_palloc(mPool, size); + } + void* pcalloc(size_t size) + { + llassert(mPool); + llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + return apr_pcalloc(mPool, size); + } +#endif + +private: + bool parent_is_being_destructed(void); + static apr_status_t s_plain_cleanup(void* userdata) { return static_cast(userdata)->plain_cleanup(); } + + apr_status_t plain_cleanup(void) + { + if (mPool && // We are not being destructed, + parent_is_being_destructed()) // but our parent is. + // This means the pool is being destructed recursively by libapr + // because one of it's parents is being destructed. + { + mPool = NULL; // Stop destroy() from destructing the pool again. + } + return APR_SUCCESS; + } +}; + +class AIAPRInitialization +{ +public: + AIAPRInitialization(void); +}; + +/** + * @brief Root memory pool (allocates memory from the operating system). + * + * This class should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase + * (and LLMutexRootPool when APR_HAS_THREADS isn't defined). + */ +class LL_COMMON_API AIAPRRootPool : public AIAPRInitialization, public AIAPRPool +{ +private: + friend class AIThreadLocalData; + friend class AIThreadSafeSimpleDCRootPool_pbase; +#if !APR_HAS_THREADS + friend class LLMutexRootPool; +#endif + //! Construct a root memory pool. + // Should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase. + AIAPRRootPool(void); + ~AIAPRRootPool(); + +private: + // Keep track of how many root pools exist and when the last one is destructed. + static bool sCountInitialized; + static apr_uint32_t volatile sCount; + +public: + // Return a global root pool that is independent of AIThreadLocalData. + // Normally you should not use this. Only use for early initialization + // (before main) and deinitialization (after main). + static AIAPRRootPool& get(void); + +#if APR_POOL_DEBUG + void grab_ownership(void) + { + // You need a patched libapr to use this. + // See http://web.archiveorange.com/archive/v/5XO9y2zoxUOMt6Gmi1OI + apr_pool_owner_set(mPool); + } +#endif + +private: + // Used for constructing the Special Global Root Pool (returned by AIAPRRootPool::get). + // It is the same as the default constructor but omits to increment sCount. As a result, + // we must be sure that at least one other AIAPRRootPool is created before termination + // of the application (which is the case: we create one AIAPRRootPool per thread). + AIAPRRootPool(int) : AIAPRInitialization(), AIAPRPool(0) { } +}; + +//! Volatile memory pool +// +// 'Volatile' APR memory pool which normally only clears memory, +// and does not destroy the pool (the same pool is reused) for +// greater efficiency. However, as a safe guard the apr pool +// is destructed every FULL_VOLATILE_APR_POOL uses to allow +// the system memory to be allocated more efficiently and not +// get scattered through RAM. +// +class LL_COMMON_API AIVolatileAPRPool : protected AIAPRPool +{ +public: + AIVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { } + + apr_pool_t* getVolatileAPRPool(void) + { + if (!mPool) create(); + ++mNumActiveRef; + ++mNumTotalRef; + return AIAPRPool::operator()(); + } + void clearVolatileAPRPool(void); + + bool isOld(void) const { return mNumTotalRef > FULL_VOLATILE_APR_POOL; } + bool isUnused() const { return mNumActiveRef == 0; } + +private: + S32 mNumActiveRef; // Number of active uses of the pool. + S32 mNumTotalRef; // Number of total uses of the pool since last creation. + + // Maximum number of references to AIVolatileAPRPool until the pool is recreated. + static S32 const FULL_VOLATILE_APR_POOL = 1024; +}; + +#endif // AIAPRPOOL_H diff --git a/linden/indra/llcommon/aithreadsafe.h b/linden/indra/llcommon/aithreadsafe.h new file mode 100644 index 000000000..70cd2a3db --- /dev/null +++ b/linden/indra/llcommon/aithreadsafe.h @@ -0,0 +1,482 @@ +/** + * @file aithreadsafe.h + * @brief Implementation of AIThreadSafe, AIReadAccessConst, AIReadAccess and AIWriteAccess. + * + * Copyright (c) 2010, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 31/03/2010 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AITHREADSAFE_H +#define AITHREADSAFE_H + +#include + +#include "llthread.h" +#include "llerror.h" + +template struct AIReadAccessConst; +template struct AIReadAccess; +template struct AIWriteAccess; +template struct AIAccess; + +template +class AIThreadSafeBits +{ +private: + // AIThreadSafe is a wrapper around an instance of T. + // Because T might not have a default constructor, it is constructed + // 'in place', with placement new, in the memory reserved here. + // + // Make sure that the memory that T will be placed in is properly + // aligned by using an array of long's. + long mMemory[(sizeof(T) + sizeof(long) - 1) / sizeof(long)]; + +public: + // The wrapped objects are constructed in-place with placement new *outside* + // of this object (by AITHREADSAFE macro(s) or derived classes). + // However, we are responsible for the destruction of the wrapped object. + ~AIThreadSafeBits() { ptr()->~T(); } + + // Only for use by AITHREADSAFE, see below. + void* memory() const { return const_cast(&mMemory[0]); } + +protected: + // Accessors. + T const* ptr() const { return reinterpret_cast(mMemory); } + T* ptr() { return reinterpret_cast(mMemory); } +}; + +/** + * @brief A wrapper class for objects that need to be accessed by more than one thread, allowing concurrent readers. + * + * Use AITHREADSAFE to define instances of any type, and use AIReadAccessConst, + * AIReadAccess and AIWriteAccess to get access to the instance. + * + * For example, + * + * + * class Foo { public: Foo(int, int); }; + * + * AITHREADSAFE(Foo, foo, (2, 3)); + * + * AIReadAccess foo_r(foo); + * // Use foo_r-> for read access. + * + * AIWriteAccess foo_w(foo); + * // Use foo_w-> for write access. + * + * + * If foo is constant, you have to use AIReadAccessConst. + * + * It is possible to pass access objects to a function that + * downgrades the access, for example: + * + * + * void readfunc(AIReadAccess const& access); + * + * AIWriteAccess foo_w(foo); + * readfunc(foo_w); // readfunc will perform read access to foo_w. + * + * + * If AIReadAccess is non-const, you can upgrade the access by creating + * an AIWriteAccess object from it. For example: + * + * + * AIWriteAccess foo_w(foo_r); + * + * + * This API is Robust(tm). If you try anything that could result in problems, + * it simply won't compile. The only mistake you can still easily make is + * to obtain write access to an object when it is not needed, or to unlock + * an object in between accesses while the state of the object should be + * preserved. For example: + * + * + * // This resets foo to point to the first file and then returns that. + * std::string filename = AIWriteAccess(foo)->get_first_filename(); + * + * // WRONG! The state between calling get_first_filename and get_next_filename should be preserved! + * + * AIWriteAccess foo_w(foo); // Wrong. The code below only needs read-access. + * while (!filename.empty()) + * { + * something(filename); + * filename = foo_w->next_filename(); + * } + * + * + * Correct would be + * + * + * AIReadAccess foo_r(foo); + * std::string filename = AIWriteAccess(foo_r)->get_first_filename(); + * while (!filename.empty()) + * { + * something(filename); + * filename = foo_r->next_filename(); + * } + * + * + */ +template +class AIThreadSafe : public AIThreadSafeBits +{ +protected: + // Only these may access the object (through ptr()). + friend struct AIReadAccessConst; + friend struct AIReadAccess; + friend struct AIWriteAccess; + + // Locking control. + AIRWLock mRWLock; + + // For use by AIThreadSafeDC + AIThreadSafe(void) { } + AIThreadSafe(AIAPRPool& parent) : mRWLock(parent) { } + +public: + // Only for use by AITHREADSAFE, see below. + AIThreadSafe(T* object) { llassert(object == AIThreadSafeBits::ptr()); } +}; + +/** + * @brief Instantiate an static, global or local object of a given type wrapped in AIThreadSafe, using an arbitrary constructor. + * + * For example, instead of doing + * + * + * Foo foo(x, y); + * static Bar bar; + * + * + * One can instantiate a thread-safe instance with + * + * + * AITHREADSAFE(Foo, foo, (x, y)); + * static AITHREADSAFE(Bar, bar, ); + * + * + * Note: This macro does not allow to allocate such object on the heap. + * If that is needed, have a look at AIThreadSafeDC. + */ +#define AITHREADSAFE(type, var, paramlist) AIThreadSafe var(new (var.memory()) type paramlist) + +/** + * @brief A wrapper class for objects that need to be accessed by more than one thread. + * + * This class is the same as an AIThreadSafe wrapper, except that it can only + * be used for default constructed objects. + * + * For example, instead of + * + * + * Foo foo; + * + * + * One would use + * + * + * AIThreadSafeDC foo; + * + * + * The advantage over AITHREADSAFE is that this object can be allocated with + * new on the heap. For example: + * + * + * AIThreadSafeDC* ptr = new AIThreadSafeDC; + * + * + * which is not possible with AITHREADSAFE. + */ +template +class AIThreadSafeDC : public AIThreadSafe +{ +public: + // Construct a wrapper around a default constructed object. + AIThreadSafeDC(void) { new (AIThreadSafe::ptr()) T; } +}; + +/** + * @brief Read lock object and provide read access. + */ +template +struct AIReadAccessConst +{ + //! Internal enum for the lock-type of the AI*Access object. + enum state_type + { + readlocked, //!< A AIReadAccessConst or AIReadAccess. + read2writelocked, //!< A AIWriteAccess constructed from a AIReadAccess. + writelocked, //!< A AIWriteAccess constructed from a AIThreadSafe. + write2writelocked //!< A AIWriteAccess constructed from (the AIReadAccess base class of) a AIWriteAccess. + }; + + //! Construct a AIReadAccessConst from a constant AIThreadSafe. + AIReadAccessConst(AIThreadSafe const& wrapper) + : mWrapper(const_cast&>(wrapper)), + mState(readlocked) + { + mWrapper.mRWLock.rdlock(); + } + + //! Destruct the AI*Access object. + // These should never be dynamically allocated, so there is no need to make this virtual. + ~AIReadAccessConst() + { + if (mState == readlocked) + mWrapper.mRWLock.rdunlock(); + else if (mState == writelocked) + mWrapper.mRWLock.wrunlock(); + else if (mState == read2writelocked) + mWrapper.mRWLock.wr2rdlock(); + } + + //! Access the underlaying object for read access. + T const* operator->() const { return mWrapper.ptr(); } + + //! Access the underlaying object for read access. + T const& operator*() const { return *mWrapper.ptr(); } + +protected: + //! Constructor used by AIReadAccess. + AIReadAccessConst(AIThreadSafe& wrapper, state_type state) + : mWrapper(wrapper), mState(state) { } + + AIThreadSafe& mWrapper; //!< Reference to the object that we provide access to. + state_type const mState; //!< The lock state that mWrapper is in. + +private: + // Disallow copy constructing directly. + AIReadAccessConst(AIReadAccessConst const&); +}; + +/** + * @brief Read lock object and provide read access, with possible promotion to write access. + */ +template +struct AIReadAccess : public AIReadAccessConst +{ + typedef typename AIReadAccessConst::state_type state_type; + using AIReadAccessConst::readlocked; + + //! Construct a AIReadAccess from a non-constant AIThreadSafe. + AIReadAccess(AIThreadSafe& wrapper) : AIReadAccessConst(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(); } + +protected: + //! Constructor used by AIWriteAccess. + AIReadAccess(AIThreadSafe& wrapper, state_type state) : AIReadAccessConst(wrapper, state) { } + + friend class AIWriteAccess; +}; + +/** + * @brief Write lock object and provide read/write access. + */ +template +struct AIWriteAccess : public AIReadAccess +{ + using AIReadAccessConst::readlocked; + using AIReadAccessConst::read2writelocked; + using AIReadAccessConst::writelocked; + using AIReadAccessConst::write2writelocked; + + //! Construct a AIWriteAccess from a non-constant AIThreadSafe. + AIWriteAccess(AIThreadSafe& wrapper) : AIReadAccess(wrapper, writelocked) { this->mWrapper.mRWLock.wrlock();} + + //! Promote read access to write access. + explicit AIWriteAccess(AIReadAccess& access) + : AIReadAccess(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked) + { + if (this->mState == read2writelocked) + { + this->mWrapper.mRWLock.rd2wrlock(); + } + } + + //! Access the underlaying object for (read and) write access. + T* operator->() const { return this->mWrapper.ptr(); } + + //! Access the underlaying object for (read and) write access. + T& operator*() const { return *this->mWrapper.ptr(); } +}; + +/** + * @brief A wrapper class for objects that need to be accessed by more than one thread. + * + * Use AITHREADSAFESIMPLE to define instances of any type, and use AIAccess + * to get access to the instance. + * + * For example, + * + * + * class Foo { public: Foo(int, int); }; + * + * AITHREADSAFESIMPLE(Foo, foo, (2, 3)); + * + * AIAccess foo_w(foo); + * // Use foo_w-> for read and write access. + * + * See also AIThreadSafe + */ +template +class AIThreadSafeSimple : public AIThreadSafeBits +{ +protected: + // Only this one may access the object (through ptr()). + friend struct AIAccess; + + // Locking control. + LLMutex mMutex; + + // For use by AIThreadSafeSimpleDC + AIThreadSafeSimple(void) { } + AIThreadSafeSimple(AIAPRPool& parent) : mMutex(parent) { } + +public: + // Only for use by AITHREADSAFESIMPLE, see below. + AIThreadSafeSimple(T* object) { llassert(object == AIThreadSafeBits::ptr()); } +}; + +/** + * @brief Instantiate an static, global or local object of a given type wrapped in AIThreadSafeSimple, using an arbitrary constructor. + * + * For example, instead of doing + * + * + * Foo foo(x, y); + * static Bar bar; + * + * + * One can instantiate a thread-safe instance with + * + * + * AITHREADSAFESIMPLE(Foo, foo, (x, y)); + * static AITHREADSAFESIMPLE(Bar, bar, ); + * + * + * Note: This macro does not allow to allocate such object on the heap. + * If that is needed, have a look at AIThreadSafeSimpleDC. + */ +#define AITHREADSAFESIMPLE(type, var, paramlist) AIThreadSafeSimple var(new (var.memory()) type paramlist) + +/** + * @brief A wrapper class for objects that need to be accessed by more than one thread. + * + * This class is the same as an AIThreadSafeSimple wrapper, except that it can only + * be used for default constructed objects. + * + * For example, instead of + * + * + * Foo foo; + * + * + * One would use + * + * + * AIThreadSafeSimpleDC foo; + * + * + * The advantage over AITHREADSAFESIMPLE is that this object can be allocated with + * new on the heap. For example: + * + * + * AIThreadSafeSimpleDC* ptr = new AIThreadSafeSimpleDC; + * + * + * which is not possible with AITHREADSAFESIMPLE. + */ +template +class AIThreadSafeSimpleDC : public AIThreadSafeSimple +{ +public: + // Construct a wrapper around a default constructed object. + AIThreadSafeSimpleDC(void) { new (AIThreadSafeSimple::ptr()) T; } + +protected: + // For use by AIThreadSafeSimpleDCRootPool + AIThreadSafeSimpleDC(AIAPRPool& parent) : AIThreadSafeSimple(parent) { new (AIThreadSafeSimple::ptr()) T; } +}; + +// Helper class for AIThreadSafeSimpleDCRootPool to assure initialization of +// the root pool before constructing AIThreadSafeSimpleDC. +class AIThreadSafeSimpleDCRootPool_pbase +{ +protected: + AIAPRRootPool mRootPool; + +private: + template friend class AIThreadSafeSimpleDCRootPool; + AIThreadSafeSimpleDCRootPool_pbase(void) { } +}; + +/** + * @brief A wrapper class for objects that need to be accessed by more than one thread. + * + * The same as AIThreadSafeSimpleDC except that this class creates its own AIAPRRootPool + * for the internally used mutexes and condition, instead of using the current threads + * root pool. The advantage of this is that it can be used for objects that need to + * be accessed from the destructors of global objects (after main). The disadvantage + * is that it's less efficient to use your own root pool, therefore it's use should be + * restricted to those cases where it is absolutely necessary. + */ +template +class AIThreadSafeSimpleDCRootPool : private AIThreadSafeSimpleDCRootPool_pbase, public AIThreadSafeSimpleDC +{ +public: + // Construct a wrapper around a default constructed object, using memory allocated + // from the operating system for the internal APR objects (mutexes and conditional), + // as opposed to allocated from the current threads root pool. + AIThreadSafeSimpleDCRootPool(void) : + AIThreadSafeSimpleDCRootPool_pbase(), + AIThreadSafeSimpleDC(mRootPool) { } +}; + +/** + * @brief Write lock object and provide read/write access. + */ +template +struct AIAccess +{ + //! Construct a AIAccess from a non-constant AIThreadSafeSimple. + AIAccess(AIThreadSafeSimple& wrapper) : mWrapper(wrapper) { this->mWrapper.mMutex.lock(); } + + //! Access the underlaying object for (read and) write access. + T* operator->() const { return this->mWrapper.ptr(); } + + //! Access the underlaying object for (read and) write access. + T& operator*() const { return *this->mWrapper.ptr(); } + + ~AIAccess() { this->mWrapper.mMutex.unlock(); } + +protected: + AIThreadSafeSimple& mWrapper; //!< Reference to the object that we provide access to. + +private: + // Disallow copy constructing directly. + AIAccess(AIAccess const&); +}; + +#endif diff --git a/linden/indra/llcommon/imageids.h b/linden/indra/llcommon/imageids.h index 7bae496e7..dc726dcf5 100644 --- a/linden/indra/llcommon/imageids.h +++ b/linden/indra/llcommon/imageids.h @@ -41,35 +41,35 @@ class LLUUID; -extern const LLUUID IMG_SMOKE; +LL_COMMON_API extern const LLUUID IMG_SMOKE; -extern const LLUUID IMG_DEFAULT; +LL_COMMON_API extern const LLUUID IMG_DEFAULT; -extern const LLUUID IMG_SUN; -extern const LLUUID IMG_MOON; -extern const LLUUID IMG_CLOUD_POOF; -extern const LLUUID IMG_SHOT; -extern const LLUUID IMG_SPARK; -extern const LLUUID IMG_FIRE; -extern const LLUUID IMG_FACE_SELECT; -extern const LLUUID IMG_DEFAULT_AVATAR; -extern const LLUUID IMG_INVISIBLE; +LL_COMMON_API extern const LLUUID IMG_SUN; +LL_COMMON_API extern const LLUUID IMG_MOON; +LL_COMMON_API extern const LLUUID IMG_CLOUD_POOF; +LL_COMMON_API extern const LLUUID IMG_SHOT; +LL_COMMON_API extern const LLUUID IMG_SPARK; +LL_COMMON_API extern const LLUUID IMG_FIRE; +LL_COMMON_API extern const LLUUID IMG_FACE_SELECT; +LL_COMMON_API extern const LLUUID IMG_DEFAULT_AVATAR; +LL_COMMON_API extern const LLUUID IMG_INVISIBLE; -extern const LLUUID IMG_EXPLOSION; -extern const LLUUID IMG_EXPLOSION_2; -extern const LLUUID IMG_EXPLOSION_3; -extern const LLUUID IMG_EXPLOSION_4; -extern const LLUUID IMG_SMOKE_POOF; +LL_COMMON_API extern const LLUUID IMG_EXPLOSION; +LL_COMMON_API extern const LLUUID IMG_EXPLOSION_2; +LL_COMMON_API extern const LLUUID IMG_EXPLOSION_3; +LL_COMMON_API extern const LLUUID IMG_EXPLOSION_4; +LL_COMMON_API extern const LLUUID IMG_SMOKE_POOF; -extern const LLUUID IMG_BIG_EXPLOSION_1; -extern const LLUUID IMG_BIG_EXPLOSION_2; +LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_1; +LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_2; -extern const LLUUID IMG_BLOOM1; -extern const LLUUID TERRAIN_DIRT_DETAIL; -extern const LLUUID TERRAIN_GRASS_DETAIL; -extern const LLUUID TERRAIN_MOUNTAIN_DETAIL; -extern const LLUUID TERRAIN_ROCK_DETAIL; +LL_COMMON_API extern const LLUUID IMG_BLOOM1; +LL_COMMON_API extern const LLUUID TERRAIN_DIRT_DETAIL; +LL_COMMON_API extern const LLUUID TERRAIN_GRASS_DETAIL; +LL_COMMON_API extern const LLUUID TERRAIN_MOUNTAIN_DETAIL; +LL_COMMON_API extern const LLUUID TERRAIN_ROCK_DETAIL; -extern const LLUUID DEFAULT_WATER_NORMAL; +LL_COMMON_API extern const LLUUID DEFAULT_WATER_NORMAL; #endif diff --git a/linden/indra/llcommon/indra_constants.h b/linden/indra/llcommon/indra_constants.h index 34d1538d3..279d280df 100644 --- a/linden/indra/llcommon/indra_constants.h +++ b/linden/indra/llcommon/indra_constants.h @@ -263,15 +263,15 @@ const U8 GOD_LIKE = 1; const U8 GOD_NOT = 0; // "agent id" for things that should be done to ALL agents -extern const LLUUID LL_UUID_ALL_AGENTS; +LL_COMMON_API extern const LLUUID LL_UUID_ALL_AGENTS; // inventory library owner -extern const LLUUID ALEXANDRIA_LINDEN_ID; +LL_COMMON_API extern const LLUUID ALEXANDRIA_LINDEN_ID; -extern const LLUUID GOVERNOR_LINDEN_ID; -extern const LLUUID REALESTATE_LINDEN_ID; +LL_COMMON_API extern const LLUUID GOVERNOR_LINDEN_ID; +LL_COMMON_API extern const LLUUID REALESTATE_LINDEN_ID; // Maintenance's group id. -extern const LLUUID MAINTENANCE_GROUP_ID; +LL_COMMON_API extern const LLUUID MAINTENANCE_GROUP_ID; // Flags for kick message const U32 KICK_FLAGS_DEFAULT = 0x0; diff --git a/linden/indra/llcommon/linden_common.h b/linden/indra/llcommon/linden_common.h index 25dd62947..bf844b99b 100644 --- a/linden/indra/llcommon/linden_common.h +++ b/linden/indra/llcommon/linden_common.h @@ -51,16 +51,16 @@ #include #include #include -#include -#include +#include -// Work Microsoft compiler warnings +// Work around Microsoft compiler warnings in STL headers #ifdef LL_WINDOWS #pragma warning (disable : 4702) // unreachable code #pragma warning (disable : 4244) // conversion from time_t to S32 #endif // LL_WINDOWS -#include +// *TODO: Eliminate these, most library .cpp files don't need them. +// Add them to llviewerprecompiledheaders.h if necessary. #include #include #include @@ -76,18 +76,21 @@ #pragma warning (disable : 4512) // assignment operator could not be generated #pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) ) #pragma warning (disable : 4265) // boost 1.36.0, non-virtual destructor in boost::exception_detail::* + +// Reenable warnings we disabled above +#pragma warning (3 : 4702) // unreachable code, we like level 3, not 4 +// moved msvc warnings to llpreprocessor.h *TODO - delete this comment after merge conflicts are unlikely -brad #endif // LL_WINDOWS // Linden only libs in alpha-order other than stdtypes.h +// *NOTE: Please keep includes here to a minimum, see above. #include "stdtypes.h" #include "lldefs.h" #include "llerror.h" #include "llextendedstatus.h" -#include "llfasttimer.h" +// Don't do this, adds 15K lines of header code to every library file. +//#include "llfasttimer.h" #include "llfile.h" #include "llformat.h" -#include "llstring.h" -#include "llsys.h" -#include "lltimer.h" #endif diff --git a/linden/indra/llcommon/llapp.cpp b/linden/indra/llcommon/llapp.cpp index 199315f34..08b145c5a 100644 --- a/linden/indra/llcommon/llapp.cpp +++ b/linden/indra/llcommon/llapp.cpp @@ -91,7 +91,6 @@ LLAppChildCallback LLApp::sDefaultChildCallback = NULL; LLApp::LLApp() : mThreadErrorp(NULL) { commonCtor(); - startErrorThread(); } void LLApp::commonCtor() @@ -119,13 +118,8 @@ void LLApp::commonCtor() mOptions.append(sd); } - // Make sure we clean up APR when we exit - // Don't need to do this if we're cleaning up APR in the destructor - //atexit(ll_cleanup_apr); - // Set the application to this instance. sApplication = this; - } LLApp::LLApp(LLErrorThread *error_thread) : @@ -420,7 +414,7 @@ void LLApp::incSigChildCount() int LLApp::getPid() { #if LL_WINDOWS - return 0; + return GetCurrentProcessId(); #else return getpid(); #endif diff --git a/linden/indra/llcommon/llapp.h b/linden/indra/llcommon/llapp.h index f8a593c33..0f5825e96 100644 --- a/linden/indra/llcommon/llapp.h +++ b/linden/indra/llcommon/llapp.h @@ -34,14 +34,17 @@ #define LL_LLAPP_H #include -#include "llapr.h" #include "llrun.h" #include "llsd.h" // Forward declarations +template class LLAtomic32; +typedef LLAtomic32 LLAtomicU32; class LLErrorThread; -class LLApp; - +class LLLiveFile; +#if LL_LINUX +typedef struct siginfo siginfo_t; +#endif typedef void (*LLAppErrorHandler)(); typedef void (*LLAppChildCallback)(int pid, bool exited, int status); @@ -62,7 +65,7 @@ class LLChildInfo }; #endif -class LLApp +class LL_COMMON_API LLApp { friend class LLErrorThread; public: @@ -189,8 +192,6 @@ class LLApp #if !LL_WINDOWS static U32 getSigChildCount(); static void incSigChildCount(); -#else -#define getpid GetCurrentProcessId #endif static int getPid(); @@ -252,9 +253,12 @@ class LLApp */ void stepFrame(); -private: + /** + * @ brief This method is called once as soon as logging is initialized. + */ void startErrorThread(); - + +private: void setupErrorHandling(); // Do platform-specific error-handling setup (signals, structured exceptions) static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred. static void runSyncErrorHandler(); // run IMMEDIATELY when we get an error, ran in the context of the faulting thread. diff --git a/linden/indra/llcommon/llapr.cpp b/linden/indra/llcommon/llapr.cpp index 7e3a26c0d..a013d9c6c 100644 --- a/linden/indra/llcommon/llapr.cpp +++ b/linden/indra/llcommon/llapr.cpp @@ -34,220 +34,7 @@ #include "linden_common.h" #include "llapr.h" - -apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool -apr_thread_mutex_t *gLogMutexp = NULL; -apr_thread_mutex_t *gCallStacksLogMutexp = NULL; - -const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool - -void ll_init_apr() -{ - if (!gAPRPoolp) - { - // Initialize APR and create the global pool - apr_initialize(); - apr_pool_create(&gAPRPoolp, NULL); - - // Initialize the logging mutex - apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp); - apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp); - - // Initialize thread-local APR pool support. - LLVolatileAPRPool::initLocalAPRFilePool(); - } -} - - -void ll_cleanup_apr() -{ - LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL; - - if (gLogMutexp) - { - // Clean up the logging mutex - - // All other threads NEED to be done before we clean up APR, so this is okay. - apr_thread_mutex_destroy(gLogMutexp); - gLogMutexp = NULL; - } - if (gCallStacksLogMutexp) - { - // Clean up the logging mutex - - // All other threads NEED to be done before we clean up APR, so this is okay. - apr_thread_mutex_destroy(gCallStacksLogMutexp); - gCallStacksLogMutexp = NULL; - } - if (gAPRPoolp) - { - apr_pool_destroy(gAPRPoolp); - gAPRPoolp = NULL; - } - apr_terminate(); -} - -// -// -//LLAPRPool -// -LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) -{ - mParent = parent ; - mReleasePoolFlag = releasePoolFlag ; - mMaxSize = size ; - mPool = NULL ; - - createAPRPool() ; -} - -LLAPRPool::~LLAPRPool() -{ - releaseAPRPool() ; -} - -void LLAPRPool::createAPRPool() -{ - if(mPool) - { - return ; - } - - mStatus = apr_pool_create(&mPool, mParent); - ll_apr_warn_status(mStatus) ; - - if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes. - { - apr_allocator_t *allocator = apr_pool_allocator_get(mPool); - if (allocator) - { - apr_allocator_max_free_set(allocator, mMaxSize) ; - } - } -} - -void LLAPRPool::releaseAPRPool() -{ - if(!mPool) - { - return ; - } - - if(!mParent || mReleasePoolFlag) - { - apr_pool_destroy(mPool) ; - mPool = NULL ; - } -} - -apr_pool_t* LLAPRPool::getAPRPool() -{ - if(!mPool) - { - createAPRPool() ; - } - - return mPool ; -} -LLVolatileAPRPool::LLVolatileAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) - : LLAPRPool(parent, size, releasePoolFlag) -{ - mNumActiveRef = 0 ; - mNumTotalRef = 0 ; -} - -apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() -{ - mNumTotalRef++ ; - mNumActiveRef++ ; - return getAPRPool() ; -} - -void LLVolatileAPRPool::clearVolatileAPRPool() -{ - if(mNumActiveRef > 0) - { - mNumActiveRef--; - if(mNumActiveRef < 1) - { - if(isFull()) - { - mNumTotalRef = 0 ; - - //destroy the apr_pool. - releaseAPRPool() ; - } - else - { - //This does not actually free the memory, - //it just allows the pool to re-use this memory for the next allocation. - apr_pool_clear(mPool) ; - } - } - } - else - { - llassert_always(mNumActiveRef > 0) ; - } - - //paranoia check if the pool is jammed. - //will remove the check before going to release. - llassert_always(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ; -} - -BOOL LLVolatileAPRPool::isFull() -{ - return mNumTotalRef > FULL_VOLATILE_APR_POOL ; -} - -#ifdef SHOW_ASSERT -// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread. -static void* gIsMainThread; -bool is_main_thread() { return gIsMainThread == LLVolatileAPRPool::getLocalAPRFilePool(); } -#endif - -// The thread private handle to access the LocalAPRFilePool. -apr_threadkey_t* LLVolatileAPRPool::sLocalAPRFilePoolKey; - -// This should be called exactly once, before the first call to createLocalAPRFilePool. -// static -void LLVolatileAPRPool::initLocalAPRFilePool() -{ - apr_status_t status = apr_threadkey_private_create(&sLocalAPRFilePoolKey, &destroyLocalAPRFilePool, gAPRPoolp); - ll_apr_assert_status(status); // Or out of memory, or system-imposed limit on the - // total number of keys per process {PTHREAD_KEYS_MAX} - // has been exceeded. - // Create the thread-local pool for the main thread (this function is called by the main thread). - createLocalAPRFilePool(); -#ifdef SHOW_ASSERT - gIsMainThread = getLocalAPRFilePool(); -#endif -} - -// This should be called once for every thread, before it uses getLocalAPRFilePool. -// static -void LLVolatileAPRPool::createLocalAPRFilePool() -{ - void* thread_local_data = new LLVolatileAPRPool; - apr_status_t status = apr_threadkey_private_set(thread_local_data, sLocalAPRFilePoolKey); - llassert_always(status == APR_SUCCESS); -} - -// This is called once for every thread when the thread is destructed. -// static -void LLVolatileAPRPool::destroyLocalAPRFilePool(void* thread_local_data) -{ - delete reinterpret_cast(thread_local_data); -} - -// static -LLVolatileAPRPool* LLVolatileAPRPool::getLocalAPRFilePool() -{ - void* thread_local_data; - apr_status_t status = apr_threadkey_private_get(&thread_local_data, sLocalAPRFilePoolKey); - llassert_always(status == APR_SUCCESS); - return reinterpret_cast(thread_local_data); -} +#include "llscopedvolatileaprpool.h" //--------------------------------------------------------------------- // @@ -310,13 +97,15 @@ void ll_apr_assert_status(apr_status_t status) // LLAPRFile::LLAPRFile() : mFile(NULL), - mCurrentFilePoolp(NULL) + mVolatileFilePoolp(NULL), + mRegularFilePoolp(NULL) { } LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type) : mFile(NULL), - mCurrentFilePoolp(NULL) + mVolatileFilePoolp(NULL), + mRegularFilePoolp(NULL) { open(filename, flags, access_type); } @@ -335,10 +124,16 @@ apr_status_t LLAPRFile::close() mFile = NULL ; } - if(mCurrentFilePoolp) + if (mVolatileFilePoolp) { - mCurrentFilePoolp->clearVolatileAPRPool() ; - mCurrentFilePoolp = NULL ; + mVolatileFilePoolp->clearVolatileAPRPool() ; + mVolatileFilePoolp = NULL ; + } + + if (mRegularFilePoolp) + { + delete mRegularFilePoolp; + mRegularFilePoolp = NULL; } return ret ; @@ -347,25 +142,28 @@ apr_status_t LLAPRFile::close() apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, access_t access_type, S32* sizep) { llassert_always(!mFile); - llassert_always(!mCurrentFilePoolp); + llassert_always(!mVolatileFilePoolp && !mRegularFilePoolp); - // Access the pool and increment it's reference count. - // The reference count of LLVolatileAPRPool objects will be decremented - // again in LLAPRFile::close by calling mCurrentFilePoolp->clearVolatileAPRPool(). - apr_pool_t* pool; - if (access_type == local) - { - // Use a "volatile" thread-local pool. - mCurrentFilePoolp = LLVolatileAPRPool::getLocalAPRFilePool(); - pool = mCurrentFilePoolp->getVolatileAPRPool(); - } - else + apr_status_t status; { - llassert(is_main_thread()); - pool = gAPRPoolp; + apr_pool_t* apr_file_open_pool; + if (access_type == local) + { + // Use a "volatile" thread-local pool. + mVolatileFilePoolp = &AIThreadLocalData::tldata().mVolatileAPRPool; + // Access the pool and increment it's reference count. + // The reference count of AIVolatileAPRPool objects will be decremented + // again in LLAPRFile::close by calling mVolatileFilePoolp->clearVolatileAPRPool(). + apr_file_open_pool = mVolatileFilePoolp->getVolatileAPRPool(); + } + else + { + mRegularFilePoolp = new AIAPRPool(AIThreadLocalData::tldata().mRootPool); + apr_file_open_pool = (*mRegularFilePoolp)(); + } + status = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_file_open_pool); } - apr_status_t s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, pool); - if (s != APR_SUCCESS || !mFile) + if (status != APR_SUCCESS || !mFile) { mFile = NULL ; close() ; @@ -373,7 +171,7 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc { *sizep = 0; } - return s; + return status; } if (sizep) @@ -390,7 +188,7 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc *sizep = file_size; } - return s; + return status; } // File I/O @@ -440,17 +238,6 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset) //static components of LLAPRFile // -// Used in the static functions below. -class LLScopedVolatileAPRFilePool { -private: - LLVolatileAPRPool* mPool; - apr_pool_t* apr_pool; -public: - LLScopedVolatileAPRFilePool() : mPool(LLVolatileAPRPool::getLocalAPRFilePool()), apr_pool(mPool->getVolatileAPRPool()) { } - ~LLScopedVolatileAPRFilePool() { mPool->clearVolatileAPRPool(); } - operator apr_pool_t*() const { return apr_pool; } -}; - //static S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset) { @@ -487,7 +274,7 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset) S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes) { apr_file_t* file_handle; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; apr_status_t s = apr_file_open(&file_handle, filename.c_str(), APR_READ|APR_BINARY, APR_OS_DEFAULT, pool); if (s != APR_SUCCESS || !file_handle) { @@ -539,7 +326,7 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n } apr_file_t* file_handle; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; apr_status_t s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool); if (s != APR_SUCCESS || !file_handle) { @@ -584,7 +371,7 @@ bool LLAPRFile::remove(const std::string& filename) { apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_file_remove(filename.c_str(), pool); if (s != APR_SUCCESS) @@ -601,7 +388,7 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname) { apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_file_rename(filename.c_str(), newname.c_str(), pool); if (s != APR_SUCCESS) @@ -619,7 +406,7 @@ bool LLAPRFile::isExist(const std::string& filename, apr_int32_t flags) apr_file_t* file_handle; apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool); if (s != APR_SUCCESS || !file_handle) @@ -640,7 +427,7 @@ S32 LLAPRFile::size(const std::string& filename) apr_finfo_t info; apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_file_open(&file_handle, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool); if (s != APR_SUCCESS || !file_handle) @@ -669,7 +456,7 @@ bool LLAPRFile::makeDir(const std::string& dirname) { apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool); if (s != APR_SUCCESS) @@ -686,7 +473,7 @@ bool LLAPRFile::removeDir(const std::string& dirname) { apr_status_t s; - LLScopedVolatileAPRFilePool pool; + LLScopedVolatileAPRPool pool; s = apr_file_remove(dirname.c_str(), pool); if (s != APR_SUCCESS) diff --git a/linden/indra/llcommon/llapr.h b/linden/indra/llcommon/llapr.h index 7f770b0ee..ded15f531 100644 --- a/linden/indra/llcommon/llapr.h +++ b/linden/indra/llcommon/llapr.h @@ -48,74 +48,8 @@ #include "apr_atomic.h" #include "llstring.h" -extern apr_thread_mutex_t* gLogMutexp; -extern apr_thread_mutex_t* gCallStacksLogMutexp; - -/** - * @brief initialize the common apr constructs -- apr itself, the - * global pool, and a mutex. - */ -void ll_init_apr(); - -/** - * @brief Cleanup those common apr constructs. - */ -void ll_cleanup_apr(); - -// -//LL apr_pool -//manage apr_pool_t, destroy allocated apr_pool in the destruction function. -// -class LLAPRPool -{ -public: - LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ; - ~LLAPRPool() ; - - apr_pool_t* getAPRPool() ; - apr_status_t getStatus() {return mStatus ; } - -protected: - void releaseAPRPool() ; - void createAPRPool() ; - -protected: - apr_pool_t* mPool ; //pointing to an apr_pool - apr_pool_t* mParent ; //parent pool - apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work. - apr_status_t mStatus ; //status when creating the pool - BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true. -}; - -// -//volatile LL apr_pool -//which clears memory automatically. -//so it can not hold static data or data after memory is cleared -// -class LLVolatileAPRPool : protected LLAPRPool -{ -public: - LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE); - ~LLVolatileAPRPool(){} - - apr_pool_t* getVolatileAPRPool() ; - - void clearVolatileAPRPool() ; - - BOOL isFull() ; - BOOL isEmpty() {return !mNumActiveRef ;} - - static void initLocalAPRFilePool(); - static void createLocalAPRFilePool(); - static void destroyLocalAPRFilePool(void* thread_local_data); - static LLVolatileAPRPool* getLocalAPRFilePool(); - -private: - S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool. - S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating. - - static apr_threadkey_t* sLocalAPRFilePoolKey; -} ; +class AIAPRPool; +class AIVolatileAPRPool; /** * @class LLScopedLock @@ -126,7 +60,7 @@ class LLVolatileAPRPool : protected LLAPRPool * destructor handles the unlock. Instances of this class are * not thread safe. */ -class LLScopedLock : private boost::noncopyable +class LL_COMMON_API LLScopedLock : private boost::noncopyable { public: /** @@ -201,12 +135,13 @@ typedef LLAtomic32 LLAtomicS32; // 2, a global pool. // -class LLAPRFile : boost::noncopyable +class LL_COMMON_API LLAPRFile : boost::noncopyable { // make this non copyable since a copy closes the file private: apr_file_t* mFile ; - LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. + AIVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use. + AIAPRPool* mRegularFilePoolp; // ...or a regular pool. public: enum access_t { @@ -257,10 +192,8 @@ class LLAPRFile : boost::noncopyable * APR_SUCCESS. * @return Returns true if status is an error condition. */ -bool ll_apr_warn_status(apr_status_t status); - -void ll_apr_assert_status(apr_status_t status); +bool LL_COMMON_API ll_apr_warn_status(apr_status_t status); -extern "C" apr_pool_t* gAPRPoolp; // Global APR memory pool +void LL_COMMON_API ll_apr_assert_status(apr_status_t status); #endif // LL_LLAPR_H diff --git a/linden/indra/llcommon/llassettype.h b/linden/indra/llcommon/llassettype.h index 4077b8d2c..9f611aec9 100644 --- a/linden/indra/llcommon/llassettype.h +++ b/linden/indra/llcommon/llassettype.h @@ -37,7 +37,7 @@ #include "stdenums.h" // for EDragAndDropType -class LLAssetType +class LL_COMMON_API LLAssetType { public: enum EType diff --git a/linden/indra/llcommon/llbase32.h b/linden/indra/llcommon/llbase32.h index 63a93e11a..47cd893d9 100644 --- a/linden/indra/llcommon/llbase32.h +++ b/linden/indra/llcommon/llbase32.h @@ -34,7 +34,7 @@ #ifndef LLBASE32_H #define LLBASE32_h -class LLBase32 +class LL_COMMON_API LLBase32 { public: static std::string encode(const U8* input, size_t input_size); diff --git a/linden/indra/llcommon/llbase64.h b/linden/indra/llcommon/llbase64.h index 58414bba8..15b27a65d 100644 --- a/linden/indra/llcommon/llbase64.h +++ b/linden/indra/llcommon/llbase64.h @@ -34,7 +34,7 @@ #ifndef LLBASE64_H #define LLBASE64_h -class LLBase64 +class LL_COMMON_API LLBase64 { public: static std::string encode(const U8* input, size_t input_size); diff --git a/linden/indra/llcommon/llcommon.cpp b/linden/indra/llcommon/llcommon.cpp index 2cbb71855..298dd4695 100644 --- a/linden/indra/llcommon/llcommon.cpp +++ b/linden/indra/llcommon/llcommon.cpp @@ -34,18 +34,10 @@ #include "llcommon.h" #include "llthread.h" -//static -BOOL LLCommon::sAprInitialized = FALSE; - //static void LLCommon::initClass() { LLMemory::initClass(); - if (!sAprInitialized) - { - ll_init_apr(); - sAprInitialized = TRUE; - } LLTimer::initClass(); LLThreadSafeRefCount::initThreadSafeRefCount(); // LLWorkerThread::initClass(); @@ -59,10 +51,5 @@ void LLCommon::cleanupClass() // LLWorkerThread::cleanupClass(); LLThreadSafeRefCount::cleanupThreadSafeRefCount(); LLTimer::cleanupClass(); - if (sAprInitialized) - { - ll_cleanup_apr(); - sAprInitialized = FALSE; - } LLMemory::cleanupClass(); } diff --git a/linden/indra/llcommon/llcommon.h b/linden/indra/llcommon/llcommon.h index 5f7798833..300ebe2b2 100644 --- a/linden/indra/llcommon/llcommon.h +++ b/linden/indra/llcommon/llcommon.h @@ -38,13 +38,11 @@ #include "lltimer.h" #include "llfile.h" -class LLCommon +class LL_COMMON_API LLCommon { public: static void initClass(); static void cleanupClass(); -private: - static BOOL sAprInitialized; }; #endif diff --git a/linden/indra/llcommon/llcrc.h b/linden/indra/llcommon/llcrc.h index 27fae7d26..74369062c 100644 --- a/linden/indra/llcommon/llcrc.h +++ b/linden/indra/llcommon/llcrc.h @@ -50,7 +50,7 @@ // llinfos << "File crc: " << crc.getCRC() << llendl; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLCRC +class LL_COMMON_API LLCRC { protected: U32 mCurrent; diff --git a/linden/indra/llcommon/llcriticaldamp.h b/linden/indra/llcommon/llcriticaldamp.h index ad98284a6..13e37d8b7 100644 --- a/linden/indra/llcommon/llcriticaldamp.h +++ b/linden/indra/llcommon/llcriticaldamp.h @@ -38,7 +38,7 @@ #include "llframetimer.h" -class LLCriticalDamp +class LL_COMMON_API LLCriticalDamp { public: LLCriticalDamp(); diff --git a/linden/indra/llcommon/llcursortypes.h b/linden/indra/llcommon/llcursortypes.h index bea70351b..836ecc3c0 100644 --- a/linden/indra/llcommon/llcursortypes.h +++ b/linden/indra/llcommon/llcursortypes.h @@ -77,6 +77,6 @@ enum ECursorType { UI_CURSOR_COUNT // Number of elements in this enum (NOT a cursor) }; -ECursorType getCursorFromString(const std::string& cursor_string); +LL_COMMON_API ECursorType getCursorFromString(const std::string& cursor_string); #endif // LL_LLCURSORTYPES_H diff --git a/linden/indra/llcommon/lldate.h b/linden/indra/llcommon/lldate.h index 5e1a4910d..d27da79ad 100644 --- a/linden/indra/llcommon/lldate.h +++ b/linden/indra/llcommon/lldate.h @@ -46,7 +46,7 @@ * * The date class represents a point in time after epoch - 1970-01-01. */ -class LLDate +class LL_COMMON_API LLDate { public: /** @@ -153,9 +153,9 @@ class LLDate }; // Helper function to stream out a date -std::ostream& operator<<(std::ostream& s, const LLDate& date); +LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLDate& date); // Helper function to stream in a date -std::istream& operator>>(std::istream& s, LLDate& date); +LL_COMMON_API std::istream& operator>>(std::istream& s, LLDate& date); #endif // LL_LLDATE_H diff --git a/linden/indra/llcommon/llerror.cpp b/linden/indra/llcommon/llerror.cpp index 30b61a916..146ec620b 100644 --- a/linden/indra/llcommon/llerror.cpp +++ b/linden/indra/llcommon/llerror.cpp @@ -46,6 +46,8 @@ # include #endif // !LL_WINDOWS #if LL_WINDOWS +# define WIN32_LEAN_AND_MEAN +# include # include #endif // LL_WINDOWS #include @@ -58,7 +60,10 @@ #include "llsd.h" #include "llsdserialize.h" #include "llstl.h" +#include "lltimer.h" +#include "aithreadsafe.h" +extern apr_thread_mutex_t* gCallStacksLogMutexp; namespace { #if !LL_WINDOWS @@ -355,12 +360,15 @@ namespace void addCallSite(LLError::CallSite&); void invalidateCallSites(); - static Globals& get(); + static AIThreadSafeSimple& get(); // return the one instance of the globals private: CallSiteVector callSites; + friend class AIThreadSafeSimpleDC; // Calls constructor. + friend class AIThreadSafeSimple; // Calls destructor. + Globals() : messageStreamInUse(false) { } @@ -384,7 +392,7 @@ namespace callSites.clear(); } - Globals& Globals::get() + AIThreadSafeSimple& Globals::get() { /* This pattern, of returning a reference to a static function variable, is to ensure that this global is constructed before @@ -392,8 +400,8 @@ namespace is. See C++ FAQ Lite, sections 10.12 through 10.14 */ - static Globals* globals = new Globals; - return *globals; + static AIThreadSafeSimpleDCRootPool* ts_globals_ptr = new AIThreadSafeSimpleDCRootPool; + return *ts_globals_ptr; } } @@ -422,13 +430,16 @@ namespace LLError int shouldLogCallCounter; - static Settings& get(); + static AIThreadSafeSimple& get(); static void reset(); - static Settings* saveAndReset(); - static void restore(Settings*); + static AIThreadSafeSimple* saveAndReset(); + static void restore(AIThreadSafeSimple*); private: + friend class AIThreadSafeBits; // Calls destructor. + friend class AIThreadSafeSimpleDC; // Calls constructor. + Settings() : printLocation(false), defaultLevel(LLError::LEVEL_DEBUG), @@ -444,53 +455,42 @@ namespace LLError for_each(recorders.begin(), recorders.end(), DeletePointer()); } - - static Settings*& getPtr(); + + static AIThreadSafeSimple* sSettings; }; + + // Pointer to current AIThreadSafeSimple object if any (NULL otherwise). + AIThreadSafeSimple* Settings::sSettings; - Settings& Settings::get() + AIThreadSafeSimple& Settings::get() { - Settings* p = getPtr(); - if (!p) + if (!sSettings) { reset(); - p = getPtr(); } - return *p; + return *sSettings; } void Settings::reset() { - Globals::get().invalidateCallSites(); - - Settings*& p = getPtr(); - delete p; - p = new Settings(); + AIAccess(Globals::get())->invalidateCallSites(); + delete sSettings; + sSettings = new AIThreadSafeSimpleDC; } - Settings* Settings::saveAndReset() + AIThreadSafeSimple* Settings::saveAndReset() { - Globals::get().invalidateCallSites(); - - Settings*& p = getPtr(); - Settings* originalSettings = p; - p = new Settings(); + AIAccess(Globals::get())->invalidateCallSites(); + AIThreadSafeSimple* originalSettings = sSettings; + sSettings = new AIThreadSafeSimpleDC; return originalSettings; } - void Settings::restore(Settings* originalSettings) - { - Globals::get().invalidateCallSites(); - - Settings*& p = getPtr(); - delete p; - p = originalSettings; - } - - Settings*& Settings::getPtr() + void Settings::restore(AIThreadSafeSimple* originalSettings) { - static Settings* currentSettings = NULL; - return currentSettings; + AIAccess(Globals::get())->invalidateCallSites(); + delete sSettings; + sSettings = originalSettings; } } @@ -594,62 +594,59 @@ namespace LLError commonInit(dir); } + void setPrintLocation(AIAccess const& settings_w, bool print) + { + settings_w->printLocation = print; + } + void setPrintLocation(bool print) { - Settings& s = Settings::get(); - s.printLocation = print; + setPrintLocation(AIAccess(Settings::get()), print); } void setFatalFunction(FatalFunction f) { - Settings& s = Settings::get(); - s.crashFunction = f; + AIAccess(Settings::get())->crashFunction = f; } void setTimeFunction(TimeFunction f) { - Settings& s = Settings::get(); - s.timeFunction = f; + AIAccess(Settings::get())->timeFunction = f; + } + + void setDefaultLevel(AIAccess const& settings_w, ELevel level) + { + AIAccess(Globals::get())->invalidateCallSites(); + settings_w->defaultLevel = level; } void setDefaultLevel(ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.defaultLevel = level; + setDefaultLevel(AIAccess(Settings::get()), level); } void setFunctionLevel(const std::string& function_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.functionLevelMap[function_name] = level; + AIAccess(Globals::get())->invalidateCallSites(); + AIAccess(Settings::get())->functionLevelMap[function_name] = level; } void setClassLevel(const std::string& class_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.classLevelMap[class_name] = level; + AIAccess(Globals::get())->invalidateCallSites(); + AIAccess(Settings::get())->classLevelMap[class_name] = level; } void setFileLevel(const std::string& file_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.fileLevelMap[file_name] = level; + AIAccess(Globals::get())->invalidateCallSites(); + AIAccess(Settings::get())->fileLevelMap[file_name] = level; } void setTagLevel(const std::string& tag_name, ELevel level) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); - g.invalidateCallSites(); - s.tagLevelMap[tag_name] = level; + AIAccess(Globals::get())->invalidateCallSites(); + AIAccess(Settings::get())->tagLevelMap[tag_name] = level; } } @@ -693,18 +690,16 @@ namespace LLError { void configure(const LLSD& config) { - Globals& g = Globals::get(); - Settings& s = Settings::get(); + AIAccess settings_w(Settings::get()); + AIAccess(Globals::get())->invalidateCallSites(); + settings_w->functionLevelMap.clear(); + settings_w->classLevelMap.clear(); + settings_w->fileLevelMap.clear(); + settings_w->tagLevelMap.clear(); + settings_w->uniqueLogMessages.clear(); - g.invalidateCallSites(); - s.functionLevelMap.clear(); - s.classLevelMap.clear(); - s.fileLevelMap.clear(); - s.tagLevelMap.clear(); - s.uniqueLogMessages.clear(); - - setPrintLocation(config["print-location"]); - setDefaultLevel(decodeLevel(config["default-level"])); + setPrintLocation(settings_w, config["print-location"]); + setDefaultLevel(settings_w, decodeLevel(config["default-level"])); LLSD sets = config["settings"]; LLSD::array_const_iterator a, end; @@ -714,10 +709,10 @@ namespace LLError ELevel level = decodeLevel(entry["level"]); - setLevels(s.functionLevelMap, entry["functions"], level); - setLevels(s.classLevelMap, entry["classes"], level); - setLevels(s.fileLevelMap, entry["files"], level); - setLevels(s.tagLevelMap, entry["tags"], level); + setLevels(settings_w->functionLevelMap, entry["functions"], level); + setLevels(settings_w->classLevelMap, entry["classes"], level); + setLevels(settings_w->fileLevelMap, entry["files"], level); + setLevels(settings_w->tagLevelMap, entry["tags"], level); } } } @@ -734,26 +729,34 @@ namespace LLError - void addRecorder(Recorder* recorder) + void addRecorder(AIAccess const& settings_w, Recorder* recorder) { if (recorder == NULL) { return; } - Settings& s = Settings::get(); - s.recorders.push_back(recorder); + settings_w->recorders.push_back(recorder); } - void removeRecorder(Recorder* recorder) + void addRecorder(Recorder* recorder) + { + addRecorder(AIAccess(Settings::get()), recorder); + } + + void removeRecorder(AIAccess const& settings_w, Recorder* recorder) { if (recorder == NULL) { return; } - Settings& s = Settings::get(); - s.recorders.erase( - std::remove(s.recorders.begin(), s.recorders.end(), recorder), - s.recorders.end()); + settings_w->recorders.erase( + std::remove(settings_w->recorders.begin(), settings_w->recorders.end(), recorder), + settings_w->recorders.end()); + } + + void removeRecorder(Recorder* recorder) + { + removeRecorder(AIAccess(Settings::get()), recorder); } } @@ -761,12 +764,12 @@ namespace LLError { void logToFile(const std::string& file_name) { - LLError::Settings& s = LLError::Settings::get(); + AIAccess settings_w(Settings::get()); - removeRecorder(s.fileRecorder); - delete s.fileRecorder; - s.fileRecorder = NULL; - s.fileRecorderFileName.clear(); + removeRecorder(settings_w, settings_w->fileRecorder); + delete settings_w->fileRecorder; + settings_w->fileRecorder = NULL; + settings_w->fileRecorderFileName.clear(); if (file_name.empty()) { @@ -780,54 +783,51 @@ namespace LLError return; } - s.fileRecorderFileName = file_name; - s.fileRecorder = f; - addRecorder(f); + settings_w->fileRecorderFileName = file_name; + settings_w->fileRecorder = f; + addRecorder(settings_w, f); } void logToFixedBuffer(LLFixedBuffer* fixedBuffer) { - LLError::Settings& s = LLError::Settings::get(); + AIAccess settings_w(Settings::get()); - removeRecorder(s.fixedBufferRecorder); - delete s.fixedBufferRecorder; - s.fixedBufferRecorder = NULL; + removeRecorder(settings_w, settings_w->fixedBufferRecorder); + delete settings_w->fixedBufferRecorder; + settings_w->fixedBufferRecorder = NULL; if (!fixedBuffer) { return; } - s.fixedBufferRecorder = new RecordToFixedBuffer(*fixedBuffer); - addRecorder(s.fixedBufferRecorder); + settings_w->fixedBufferRecorder = new RecordToFixedBuffer(*fixedBuffer); + addRecorder(settings_w, settings_w->fixedBufferRecorder); } std::string logFileName() { - LLError::Settings& s = LLError::Settings::get(); - return s.fileRecorderFileName; + return AIAccess(Settings::get())->fileRecorderFileName; } } namespace { - void writeToRecorders(LLError::ELevel level, const std::string& message) + void writeToRecorders(AIAccess const& settings_w, LLError::ELevel level, const std::string& message) { - LLError::Settings& s = LLError::Settings::get(); - std::string messageWithTime; - - for (Recorders::const_iterator i = s.recorders.begin(); - i != s.recorders.end(); + + for (Recorders::const_iterator i = settings_w->recorders.begin(); + i != settings_w->recorders.end(); ++i) { LLError::Recorder* r = *i; - if (r->wantsTime() && s.timeFunction != NULL) + if (r->wantsTime() && settings_w->timeFunction != NULL) { if (messageWithTime.empty()) { - messageWithTime = s.timeFunction() + " " + message; + messageWithTime = settings_w->timeFunction() + " " + message; } r->recordMessage(level, messageWithTime); @@ -869,6 +869,9 @@ You get: */ +apr_thread_mutex_t* gLogMutexp; +apr_thread_mutex_t* gCallStacksLogMutexp; + namespace { bool checkLevelMap(const LevelMap& map, const std::string& key, LLError::ELevel& level) @@ -942,10 +945,9 @@ namespace LLError return false; } - Globals& g = Globals::get(); - Settings& s = Settings::get(); + AIAccess settings_w(Settings::get()); - s.shouldLogCallCounter += 1; + settings_w->shouldLogCallCounter += 1; std::string class_name = className(site.mClassInfo); std::string function_name = functionName(site.mFunction); @@ -954,20 +956,20 @@ namespace LLError function_name = class_name + "::" + function_name; } - ELevel compareLevel = s.defaultLevel; + ELevel compareLevel = settings_w->defaultLevel; // The most specific match found will be used as the log level, // since the computation short circuits. // So, in increasing order of importance: // Default < Broad Tag < File < Class < Function < Narrow Tag - ((site.mNarrowTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mNarrowTag, compareLevel) : false) - || checkLevelMap(s.functionLevelMap, function_name, compareLevel) - || checkLevelMap(s.classLevelMap, class_name, compareLevel) - || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel) - || ((site.mBroadTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mBroadTag, compareLevel) : false); + ((site.mNarrowTag != NULL) ? checkLevelMap(settings_w->tagLevelMap, site.mNarrowTag, compareLevel) : false) + || checkLevelMap(settings_w->functionLevelMap, function_name, compareLevel) + || checkLevelMap(settings_w->classLevelMap, class_name, compareLevel) + || checkLevelMap(settings_w->fileLevelMap, abbreviateFile(site.mFile), compareLevel) + || ((site.mBroadTag != NULL) ? checkLevelMap(settings_w->tagLevelMap, site.mBroadTag, compareLevel) : false); site.mCached = true; - g.addCallSite(site); + AIAccess(Globals::get())->addCallSite(site); return site.mShouldLog = site.mLevel >= compareLevel; } @@ -977,16 +979,16 @@ namespace LLError LogLock lock; if (lock.ok()) { - Globals& g = Globals::get(); + AIAccess globals(Globals::get()); - if (!g.messageStreamInUse) + if (!globals->messageStreamInUse) { - g.messageStreamInUse = true; - return &g.messageStream; + globals->messageStreamInUse = true; + return &globals->messageStream; // Returns pointer to member of unlocked object, apparently "protected" by having set globals->messageStreamInUse. } } - return new std::ostringstream; + return new std::ostringstream; // Holy memory leak. } void Log::flush(std::ostringstream* out, char* message) @@ -1007,12 +1009,12 @@ namespace LLError message[127] = '\0' ; } - Globals& g = Globals::get(); - if (out == &g.messageStream) + AIAccess globals(Globals::get()); + if (out == &globals->messageStream) { - g.messageStream.clear(); - g.messageStream.str(""); - g.messageStreamInUse = false; + globals->messageStream.clear(); + globals->messageStream.str(""); + globals->messageStreamInUse = false; } else { @@ -1029,28 +1031,31 @@ namespace LLError return; } - Globals& g = Globals::get(); - Settings& s = Settings::get(); - std::string message = out->str(); - if (out == &g.messageStream) - { - g.messageStream.clear(); - g.messageStream.str(""); - g.messageStreamInUse = false; - } - else + { - delete out; + AIAccess globals(Globals::get()); + if (out == &globals->messageStream) + { + globals->messageStream.clear(); + globals->messageStream.str(""); + globals->messageStreamInUse = false; + } + else + { + delete out; + } } + AIAccess settings_w(Settings::get()); + if (site.mLevel == LEVEL_ERROR) { std::ostringstream fatalMessage; fatalMessage << abbreviateFile(site.mFile) << "(" << site.mLine << ") : error"; - writeToRecorders(site.mLevel, fatalMessage.str()); + writeToRecorders(settings_w, site.mLevel, fatalMessage.str()); } @@ -1065,7 +1070,7 @@ namespace LLError default: prefix << "XXX: "; break; }; - if (s.printLocation) + if (settings_w->printLocation) { prefix << abbreviateFile(site.mFile) << "(" << site.mLine << ") : "; @@ -1083,8 +1088,8 @@ namespace LLError if (site.mPrintOnce) { - std::map::iterator messageIter = s.uniqueLogMessages.find(message); - if (messageIter != s.uniqueLogMessages.end()) + std::map::iterator messageIter = settings_w->uniqueLogMessages.find(message); + if (messageIter != settings_w->uniqueLogMessages.end()) { messageIter->second++; unsigned int num_messages = messageIter->second; @@ -1100,14 +1105,14 @@ namespace LLError else { prefix << "ONCE: "; - s.uniqueLogMessages[message] = 1; + settings_w->uniqueLogMessages[message] = 1; } } if (site.mPrintOnce) { - std::map::iterator messageIter = s.uniqueLogMessages.find(message); - if (messageIter != s.uniqueLogMessages.end()) + std::map::iterator messageIter = settings_w->uniqueLogMessages.find(message); + if (messageIter != settings_w->uniqueLogMessages.end()) { messageIter->second++; unsigned int num_messages = messageIter->second; @@ -1123,18 +1128,18 @@ namespace LLError else { prefix << "ONCE: "; - s.uniqueLogMessages[message] = 1; + settings_w->uniqueLogMessages[message] = 1; } } prefix << message; message = prefix.str(); - writeToRecorders(site.mLevel, message); + writeToRecorders(settings_w, site.mLevel, message); - if (site.mLevel == LEVEL_ERROR && s.crashFunction) + if (site.mLevel == LEVEL_ERROR && settings_w->crashFunction) { - s.crashFunction(message); + settings_w->crashFunction(message); } } } @@ -1144,14 +1149,16 @@ namespace LLError namespace LLError { - Settings* saveAndResetSettings() + class ThreadSafeSettings { }; + + ThreadSafeSettings* saveAndResetSettings() { - return Settings::saveAndReset(); + return reinterpret_cast(Settings::saveAndReset()); } - void restoreSettings(Settings* s) + void restoreSettings(ThreadSafeSettings* s) { - return Settings::restore(s); + Settings::restore(reinterpret_cast*>(s)); } std::string removePrefix(std::string& s, const std::string& p) @@ -1197,8 +1204,7 @@ namespace LLError int shouldLogCallCount() { - Settings& s = Settings::get(); - return s.shouldLogCallCounter; + return AIAccess(Settings::get())->shouldLogCallCounter; } #if LL_WINDOWS diff --git a/linden/indra/llcommon/llerror.h b/linden/indra/llcommon/llerror.h index 37e922d4b..5a4c64485 100644 --- a/linden/indra/llcommon/llerror.h +++ b/linden/indra/llcommon/llerror.h @@ -131,7 +131,7 @@ namespace LLError class CallSite; - class Log + class LL_COMMON_API Log { public: static bool shouldLog(CallSite&); @@ -140,7 +140,7 @@ namespace LLError static void flush(std::ostringstream*, const CallSite&); }; - class CallSite + class LL_COMMON_API CallSite { // Represents a specific place in the code where a message is logged // This is public because it is used by the macros below. It is not @@ -189,7 +189,7 @@ namespace LLError //LLCallStacks is designed not to be thread-safe. //so try not to use it in multiple parallel threads at same time. //Used in a single thread at a time is fine. - class LLCallStacks + class LL_COMMON_API LLCallStacks { private: static char** sBuffer ; diff --git a/linden/indra/llcommon/llerrorcontrol.h b/linden/indra/llcommon/llerrorcontrol.h index a55d706d2..c086f27a7 100644 --- a/linden/indra/llcommon/llerrorcontrol.h +++ b/linden/indra/llcommon/llerrorcontrol.h @@ -52,12 +52,12 @@ class LLSD; namespace LLError { - void initForServer(const std::string& identity); + LL_COMMON_API void initForServer(const std::string& identity); // resets all logging settings to defaults needed by server processes // logs to stderr, syslog, and windows debug log // the identity string is used for in the syslog - void initForApplication(const std::string& dir); + LL_COMMON_API void initForApplication(const std::string& dir); // resets all logging settings to defaults needed by applicaitons // logs to stderr and windows debug log // sets up log configuration from the file logcontrol.xml in dir @@ -68,13 +68,14 @@ namespace LLError Setting a level means log messages at that level or above. */ - void setPrintLocation(bool); - void setDefaultLevel(LLError::ELevel); - void setFunctionLevel(const std::string& function_name, LLError::ELevel); - void setClassLevel(const std::string& class_name, LLError::ELevel); - void setFileLevel(const std::string& file_name, LLError::ELevel); + LL_COMMON_API void setPrintLocation(bool); + LL_COMMON_API void setDefaultLevel(LLError::ELevel); + LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel); + LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel); + LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel); + LL_COMMON_API void setTagLevel(const std::string& file_name, LLError::ELevel); - void configure(const LLSD&); + LL_COMMON_API void configure(const LLSD&); // the LLSD can configure all of the settings // usually read automatically from the live errorlog.xml file @@ -84,25 +85,25 @@ namespace LLError */ typedef void(*FatalFunction)(const std::string& message); - void crashAndLoop(const std::string& message); + LL_COMMON_API void crashAndLoop(const std::string& message); // Default fatal funtion: access null pointer and loops forever - void setFatalFunction(FatalFunction); + LL_COMMON_API void setFatalFunction(FatalFunction); // The fatal function will be called when an message of LEVEL_ERROR // is logged. Note: supressing a LEVEL_ERROR message from being logged // (by, for example, setting a class level to LEVEL_NONE), will keep // the that message from causing the fatal funciton to be invoked. typedef std::string (*TimeFunction)(); - std::string utcTime(); + LL_COMMON_API std::string utcTime(); - void setTimeFunction(TimeFunction); + LL_COMMON_API void setTimeFunction(TimeFunction); // The function is use to return the current time, formatted for // display by those error recorders that want the time included. - class Recorder + class LL_COMMON_API Recorder { // An object that handles the actual output or error messages. public: @@ -116,17 +117,17 @@ namespace LLError // included in the text of the message }; - void addRecorder(Recorder*); - void removeRecorder(Recorder*); + LL_COMMON_API void addRecorder(Recorder*); + LL_COMMON_API void removeRecorder(Recorder*); // each error message is passed to each recorder via recordMessage() - void logToFile(const std::string& filename); - void logToFixedBuffer(LLFixedBuffer*); + LL_COMMON_API void logToFile(const std::string& filename); + LL_COMMON_API void logToFixedBuffer(LLFixedBuffer*); // Utilities to add recorders for logging to a file or a fixed buffer // A second call to the same function will remove the logger added // with the first. // Passing the empty string or NULL to just removes any prior. - std::string logFileName(); + LL_COMMON_API std::string logFileName(); // returns name of current logging file, empty string if none @@ -134,12 +135,12 @@ namespace LLError Utilities for use by the unit tests of LLError itself. */ - class Settings; - Settings* saveAndResetSettings(); - void restoreSettings(Settings *); + class ThreadSafeSettings; + LL_COMMON_API ThreadSafeSettings* saveAndResetSettings(); + LL_COMMON_API void restoreSettings(ThreadSafeSettings *); - std::string abbreviateFile(const std::string& filePath); - int shouldLogCallCount(); + LL_COMMON_API std::string abbreviateFile(const std::string& filePath); + LL_COMMON_API int shouldLogCallCount(); }; diff --git a/linden/indra/llcommon/llerrorthread.cpp b/linden/indra/llcommon/llerrorthread.cpp index 4c779c58c..e2b106aa2 100644 --- a/linden/indra/llcommon/llerrorthread.cpp +++ b/linden/indra/llcommon/llerrorthread.cpp @@ -32,6 +32,7 @@ #include "linden_common.h" #include "llerrorthread.h" #include "llapp.h" +#include "lltimer.h" LLErrorThread::LLErrorThread() : LLThread("Error"), diff --git a/linden/indra/llcommon/llerrorthread.h b/linden/indra/llcommon/llerrorthread.h index f1d6ffc34..3121d2967 100644 --- a/linden/indra/llcommon/llerrorthread.h +++ b/linden/indra/llcommon/llerrorthread.h @@ -35,7 +35,7 @@ #include "llthread.h" -class LLErrorThread : public LLThread +class LL_COMMON_API LLErrorThread : public LLThread { public: LLErrorThread(); diff --git a/linden/indra/llcommon/llevent.h b/linden/indra/llcommon/llevent.h index 60887a060..6b223a8ee 100644 --- a/linden/indra/llcommon/llevent.h +++ b/linden/indra/llcommon/llevent.h @@ -44,7 +44,7 @@ class LLEventDispatcher; class LLObservable; // Abstract event. All events derive from LLEvent -class LLEvent : public LLThreadSafeRefCount +class LL_COMMON_API LLEvent : public LLThreadSafeRefCount { protected: virtual ~LLEvent(); @@ -72,7 +72,7 @@ class LLEvent : public LLThreadSafeRefCount }; // Abstract listener. All listeners derive from LLEventListener -class LLEventListener : public LLThreadSafeRefCount +class LL_COMMON_API LLEventListener : public LLThreadSafeRefCount { protected: virtual ~LLEventListener(); @@ -89,7 +89,7 @@ class LLEventListener : public LLThreadSafeRefCount }; // A listener which tracks references to it and cleans up when it's deallocated -class LLSimpleListener : public LLEventListener +class LL_COMMON_API LLSimpleListener : public LLEventListener { public: void clearDispatchers(); @@ -114,7 +114,7 @@ struct LLListenerEntry // Base class for a dispatcher - an object which listens // to events being fired and relays them to their // appropriate destinations. -class LLEventDispatcher : public LLThreadSafeRefCount +class LL_COMMON_API LLEventDispatcher : public LLThreadSafeRefCount { protected: virtual ~LLEventDispatcher(); @@ -157,7 +157,7 @@ class LLEventDispatcher : public LLThreadSafeRefCount // In order for this class to work properly, it needs // an instance of an LLEventDispatcher to route events to their // listeners. -class LLObservable +class LL_COMMON_API LLObservable { public: // Initialize with the default Dispatcher diff --git a/linden/indra/llcommon/llfasttimer.cpp b/linden/indra/llcommon/llfasttimer.cpp index 4aa23bb47..5f091d5db 100644 --- a/linden/indra/llcommon/llfasttimer.cpp +++ b/linden/indra/llcommon/llfasttimer.cpp @@ -42,6 +42,7 @@ #include #elif LL_DARWIN #include +#include "lltimer.h" // get_clock_count() #else #error "architecture not supported" #endif diff --git a/linden/indra/llcommon/llfasttimer.h b/linden/indra/llcommon/llfasttimer.h index 8c1cf4712..602a2f7c7 100644 --- a/linden/indra/llcommon/llfasttimer.h +++ b/linden/indra/llcommon/llfasttimer.h @@ -35,9 +35,9 @@ #define FAST_TIMER_ON 1 -U64 get_cpu_clock_count(); +LL_COMMON_API U64 get_cpu_clock_count(); -class LLFastTimer +class LL_COMMON_API LLFastTimer { public: enum EFastTimerType diff --git a/linden/indra/llcommon/llfile.cpp b/linden/indra/llcommon/llfile.cpp index 2a76f7fb8..6b6863019 100644 --- a/linden/indra/llcommon/llfile.cpp +++ b/linden/indra/llcommon/llfile.cpp @@ -34,6 +34,8 @@ */ #if LL_WINDOWS +# define WIN32_LEAN_AND_MEAN +# include #include #endif diff --git a/linden/indra/llcommon/llfile.h b/linden/indra/llcommon/llfile.h index c6092f7b9..ee376054b 100644 --- a/linden/indra/llcommon/llfile.h +++ b/linden/indra/llcommon/llfile.h @@ -70,7 +70,7 @@ typedef struct stat llstat; #include "llstring.h" // safe char* -> std::string conversion -class LLFile +class LL_COMMON_API LLFile { public: // All these functions take UTF8 path/filenames. @@ -95,7 +95,7 @@ class LLFile #if USE_LLFILESTREAMS -class llifstream : public std::basic_istream < char , std::char_traits < char > > +class LL_COMMON_API llifstream : public std::basic_istream < char , std::char_traits < char > > { // input stream associated with a C stream public: @@ -136,7 +136,7 @@ class llifstream : public std::basic_istream < char , std::char_traits < char > }; -class llofstream : public std::basic_ostream< char , std::char_traits < char > > +class LL_COMMON_API llofstream : public std::basic_ostream< char , std::char_traits < char > > { public: typedef std::basic_ostream< char , std::char_traits < char > > _Myt; @@ -185,7 +185,7 @@ class llofstream : public std::basic_ostream< char , std::char_traits < char > > //#define llifstream std::ifstream //#define llofstream std::ofstream -class llifstream : public std::ifstream +class LL_COMMON_API llifstream : public std::ifstream { public: llifstream() : std::ifstream() @@ -203,7 +203,7 @@ class llifstream : public std::ifstream }; -class llofstream : public std::ofstream +class LL_COMMON_API llofstream : public std::ofstream { public: llofstream() : std::ofstream() diff --git a/linden/indra/llcommon/llfindlocale.cpp b/linden/indra/llcommon/llfindlocale.cpp index 505f5c540..71675af01 100644 --- a/linden/indra/llcommon/llfindlocale.cpp +++ b/linden/indra/llcommon/llfindlocale.cpp @@ -39,6 +39,8 @@ #include #ifdef WIN32 +# define WIN32_LEAN_AND_MEAN +# include #include #include #endif diff --git a/linden/indra/llcommon/llfindlocale.h b/linden/indra/llcommon/llfindlocale.h index f17c7740f..b812a065d 100644 --- a/linden/indra/llcommon/llfindlocale.h +++ b/linden/indra/llcommon/llfindlocale.h @@ -59,8 +59,8 @@ typedef enum { /* This allocates/fills in a FL_Locale structure with pointers to strings (which should be treated as static), or NULL for inappropriate / undetected fields. */ -FL_Success FL_FindLocale(FL_Locale **locale, FL_Domain domain); +LL_COMMON_API FL_Success FL_FindLocale(FL_Locale **locale, FL_Domain domain); /* This should be used to free the struct written by FL_FindLocale */ -void FL_FreeLocale(FL_Locale **locale); +LL_COMMON_API void FL_FreeLocale(FL_Locale **locale); #endif /*__findlocale_h_*/ diff --git a/linden/indra/llcommon/llfixedbuffer.cpp b/linden/indra/llcommon/llfixedbuffer.cpp index e9d602937..37a12add8 100644 --- a/linden/indra/llcommon/llfixedbuffer.cpp +++ b/linden/indra/llcommon/llfixedbuffer.cpp @@ -33,9 +33,8 @@ #include "llfixedbuffer.h" LLFixedBuffer::LLFixedBuffer(const U32 max_lines) - : mMutex(NULL) + : mMaxLines(max_lines) { - mMaxLines = max_lines; mTimer.reset(); } diff --git a/linden/indra/llcommon/llfixedbuffer.h b/linden/indra/llcommon/llfixedbuffer.h index 992a024df..51d070173 100644 --- a/linden/indra/llcommon/llfixedbuffer.h +++ b/linden/indra/llcommon/llfixedbuffer.h @@ -41,7 +41,7 @@ // Fixed size buffer for console output and other things. -class LLFixedBuffer +class LL_COMMON_API LLFixedBuffer { public: LLFixedBuffer(const U32 max_lines = 20); diff --git a/linden/indra/llcommon/llformat.h b/linden/indra/llcommon/llformat.h index 44c62d971..ad30d4fb1 100644 --- a/linden/indra/llcommon/llformat.h +++ b/linden/indra/llcommon/llformat.h @@ -40,6 +40,6 @@ // *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun) // should perhaps be replaced with boost::format. -std::string llformat(const char *fmt, ...); +LL_COMMON_API std::string llformat(const char *fmt, ...); #endif // LL_LLFORMAT_H diff --git a/linden/indra/llcommon/llframetimer.h b/linden/indra/llcommon/llframetimer.h index 8f51272af..f4775a992 100644 --- a/linden/indra/llcommon/llframetimer.h +++ b/linden/indra/llcommon/llframetimer.h @@ -43,7 +43,7 @@ #include "lltimer.h" #include "timing.h" -class LLFrameTimer +class LL_COMMON_API LLFrameTimer { public: LLFrameTimer() : mStartTime( sFrameTime ), mExpiry(0), mStarted(TRUE) {} diff --git a/linden/indra/llcommon/llheartbeat.h b/linden/indra/llcommon/llheartbeat.h index fecb5b1e5..6f7026970 100644 --- a/linden/indra/llcommon/llheartbeat.h +++ b/linden/indra/llcommon/llheartbeat.h @@ -40,7 +40,7 @@ // Note: Win32 does not support the heartbeat/smackdown system; // heartbeat-delivery turns into a no-op there. -class LLHeartbeat +class LL_COMMON_API LLHeartbeat { public: // secs_between_heartbeat: after a heartbeat is successfully delivered, diff --git a/linden/indra/llcommon/llliveappconfig.h b/linden/indra/llcommon/llliveappconfig.h index 55d84a477..3251a7c50 100644 --- a/linden/indra/llcommon/llliveappconfig.h +++ b/linden/indra/llcommon/llliveappconfig.h @@ -37,7 +37,7 @@ class LLApp; -class LLLiveAppConfig : public LLLiveFile +class LL_COMMON_API LLLiveAppConfig : public LLLiveFile { public: // To use this, instantiate a LLLiveAppConfig object inside your main loop. diff --git a/linden/indra/llcommon/lllivefile.h b/linden/indra/llcommon/lllivefile.h index fddf00622..72f16fd99 100644 --- a/linden/indra/llcommon/lllivefile.h +++ b/linden/indra/llcommon/lllivefile.h @@ -36,7 +36,7 @@ const F32 configFileRefreshRate = 5.0; // seconds -class LLLiveFile +class LL_COMMON_API LLLiveFile { public: LLLiveFile(const std::string &filename, const F32 refresh_period = 5.f); diff --git a/linden/indra/llcommon/lllog.h b/linden/indra/llcommon/lllog.h index 7ac6c8aa4..4b6777bb9 100644 --- a/linden/indra/llcommon/lllog.h +++ b/linden/indra/llcommon/lllog.h @@ -41,7 +41,7 @@ class LLLogImpl; class LLApp; class LLSD; -class LLLog +class LL_COMMON_API LLLog { public: LLLog(LLApp* app); diff --git a/linden/indra/llcommon/lllslconstants.h b/linden/indra/llcommon/lllslconstants.h old mode 100644 new mode 100755 index a24c0a81b..25a15e4e6 --- a/linden/indra/llcommon/lllslconstants.h +++ b/linden/indra/llcommon/lllslconstants.h @@ -5,7 +5,7 @@ * * $LicenseInfo:firstyear=2006&license=viewergpl$ * - * Copyright (c) 2006-2009, Linden Research, Inc. + * Copyright (c) 2006-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab diff --git a/linden/indra/llcommon/llmd5.cpp b/linden/indra/llcommon/llmd5.cpp index 14b4f9f4b..887979bbf 100644 --- a/linden/indra/llcommon/llmd5.cpp +++ b/linden/indra/llcommon/llmd5.cpp @@ -83,6 +83,7 @@ documentation and/or software. #include "llmd5.h" #include +#include // how many bytes to grab at a time when checking files const int LLMD5::BLOCK_LEN = 4096; diff --git a/linden/indra/llcommon/llmd5.h b/linden/indra/llcommon/llmd5.h index d8bca03e4..df9d7324a 100644 --- a/linden/indra/llcommon/llmd5.h +++ b/linden/indra/llcommon/llmd5.h @@ -80,7 +80,7 @@ const int MD5RAW_BYTES = 16; const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null const int MD5HEX_STR_BYTES = 32; // message system fixed size -class LLMD5 { +class LL_COMMON_API LLMD5 { // first, some types: typedef unsigned int uint4; // assumes integer is 4 words long typedef unsigned short int uint2; // assumes short integer is 2 words long diff --git a/linden/indra/llcommon/llmemory.cpp b/linden/indra/llcommon/llmemory.cpp index a6de3d2d6..2b01442be 100644 --- a/linden/indra/llcommon/llmemory.cpp +++ b/linden/indra/llcommon/llmemory.cpp @@ -33,6 +33,8 @@ #include "linden_common.h" #if defined(LL_WINDOWS) +# define WIN32_LEAN_AND_MEAN +# include # include # include #elif defined(LL_DARWIN) @@ -283,6 +285,11 @@ LLRefCount::LLRefCount() : { } +LLRefCount::LLRefCount(const LLRefCount& other) +: mRef(0) +{ +} + LLRefCount::~LLRefCount() { if (mRef != 0) @@ -290,7 +297,13 @@ LLRefCount::~LLRefCount() llerrs << "deleting non-zero reference" << llendl; } } - + +LLRefCount& LLRefCount::operator=(const LLRefCount&) +{ + // do nothing, since ref count is specific to *this* reference + return *this; +} + //---------------------------------------------------------------------------- #if defined(LL_WINDOWS) diff --git a/linden/indra/llcommon/llmemory.h b/linden/indra/llcommon/llmemory.h index b5c071148..9aa4b857e 100644 --- a/linden/indra/llcommon/llmemory.h +++ b/linden/indra/llcommon/llmemory.h @@ -45,7 +45,7 @@ const U32 LLREFCOUNT_SENTINEL_VALUE = 0xAAAAAAAA; //---------------------------------------------------------------------------- -class LLMemory +class LL_COMMON_API LLMemory { public: static void initClass(); @@ -68,12 +68,12 @@ class LLMemory //---------------------------------------------------------------------------- -class LLRefCount +class LL_COMMON_API LLRefCount { protected: - LLRefCount(const LLRefCount&); // not implemented + LLRefCount(const LLRefCount&); private: - LLRefCount&operator=(const LLRefCount&); // not implemented + LLRefCount&operator=(const LLRefCount&); protected: virtual ~LLRefCount(); // use unref() @@ -467,6 +467,6 @@ class LLSingleton // Return the resident set size of the current process, in bytes. // Return value is zero if not known. -U64 getCurrentRSS(); +LL_COMMON_API U64 getCurrentRSS(); #endif diff --git a/linden/indra/llcommon/llmemorystream.h b/linden/indra/llcommon/llmemorystream.h index f3486324c..fa0f5d22f 100644 --- a/linden/indra/llcommon/llmemorystream.h +++ b/linden/indra/llcommon/llmemorystream.h @@ -52,7 +52,7 @@ * be careful to always pass in a valid memory location that exists * for at least as long as this streambuf. */ -class LLMemoryStreamBuf : public std::streambuf +class LL_COMMON_API LLMemoryStreamBuf : public std::streambuf { public: LLMemoryStreamBuf(const U8* start, S32 length); @@ -74,7 +74,7 @@ class LLMemoryStreamBuf : public std::streambuf * be careful to always pass in a valid memory location that exists * for at least as long as this streambuf. */ -class LLMemoryStream : public std::istream +class LL_COMMON_API LLMemoryStream : public std::istream { public: LLMemoryStream(const U8* start, S32 length); diff --git a/linden/indra/llcommon/llmemtype.h b/linden/indra/llcommon/llmemtype.h index a9ebc2062..d4cc67ea4 100644 --- a/linden/indra/llcommon/llmemtype.h +++ b/linden/indra/llcommon/llmemtype.h @@ -57,7 +57,7 @@ static void operator delete(void* p) { ll_release(p); } //---------------------------------------------------------------------------- -class LLMemType +class LL_COMMON_API LLMemType { public: // Also update sTypeDesc in llmemory.cpp diff --git a/linden/indra/llcommon/llmetrics.h b/linden/indra/llcommon/llmetrics.h index 1d91e8c8a..f6f49eb45 100644 --- a/linden/indra/llcommon/llmetrics.h +++ b/linden/indra/llcommon/llmetrics.h @@ -38,7 +38,7 @@ class LLMetricsImpl; class LLSD; -class LLMetrics +class LL_COMMON_API LLMetrics { public: LLMetrics(); diff --git a/linden/indra/llcommon/llmortician.h b/linden/indra/llcommon/llmortician.h index 247632f52..55a101a97 100644 --- a/linden/indra/llcommon/llmortician.h +++ b/linden/indra/llcommon/llmortician.h @@ -35,7 +35,7 @@ #include "stdtypes.h" -class LLMortician +class LL_COMMON_API LLMortician { public: LLMortician() { mIsDead = FALSE; } diff --git a/linden/indra/llcommon/llpreprocessor.h b/linden/indra/llcommon/llpreprocessor.h index 2e4fd4787..6886e3a34 100644 --- a/linden/indra/llcommon/llpreprocessor.h +++ b/linden/indra/llcommon/llpreprocessor.h @@ -92,47 +92,63 @@ #endif - // Deal with the differeneces on Windows -#if LL_MSVC -namespace snprintf_hack -{ - int snprintf(char *str, size_t size, const char *format, ...); -} - -// #define snprintf safe_snprintf /* Flawfinder: ignore */ -using snprintf_hack::snprintf; -#endif // LL_MSVC - -// Static linking with apr on windows needs to be declared. -#ifdef LL_WINDOWS -#ifndef APR_DECLARE_STATIC -#define APR_DECLARE_STATIC // For APR on Windows -#endif -#ifndef APU_DECLARE_STATIC -#define APU_DECLARE_STATIC // For APR util on Windows -#endif -#endif - #if defined(LL_WINDOWS) #define BOOST_REGEX_NO_LIB 1 #define CURL_STATICLIB 1 #define XML_STATIC #endif // LL_WINDOWS - // Deal with VC6 problems #if LL_MSVC #pragma warning( 3 : 4701 ) // "local variable used without being initialized" Treat this as level 3, not level 4. #pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4. #pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4. //#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4. +#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function +#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden" #pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual" -#pragma warning( disable : 4786 ) // silly MS warning deep inside their include file +//#pragma warning( disable : 4265 ) // boost 1.36.0, non-virtual destructor in boost::exception_detail::* +#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden +#pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored #pragma warning( disable : 4284 ) // silly MS warning deep inside their include file #pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. #pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) #pragma warning( disable : 4996 ) // warning: deprecated + +// Linker optimization with "extern template" generates these warnings +#pragma warning( disable : 4231 ) // nonstandard extension used : 'extern' before template explicit instantiation +#pragma warning( disable : 4506 ) // no definition for inline function + +// level 4 warnings that we need to disable: +#pragma warning (disable : 4100) // unreferenced formal parameter +#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) ) +#pragma warning (disable : 4244) // possible loss of data on conversions +#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template +#pragma warning (disable : 4512) // assignment operator could not be generated +#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) ) + +#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class +#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class #endif // LL_MSVC +#if LL_WINDOWS +#define LL_DLLEXPORT __declspec(dllexport) +#define LL_DLLIMPORT __declspec(dllimport) +#elif LL_LINUX +#define LL_DLLEXPORT __attribute__ ((visibility("default"))) +#define LL_DLLIMPORT +#else +#define LL_DLLEXPORT +#define LL_DLLIMPORT +#endif // LL_WINDOWS + +#ifdef llcommon_EXPORTS +// Compiling llcommon (shared) +#define LL_COMMON_API LL_DLLEXPORT +#else // llcommon_EXPORTS +// Using llcommon (shared) +#define LL_COMMON_API LL_DLLIMPORT +#endif // llcommon_EXPORTS + #endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/linden/indra/llcommon/llprocesslauncher.cpp b/linden/indra/llcommon/llprocesslauncher.cpp new file mode 100644 index 000000000..e27aaa3c5 --- /dev/null +++ b/linden/indra/llcommon/llprocesslauncher.cpp @@ -0,0 +1,346 @@ +/** + * @file llprocesslauncher.cpp + * @brief Utility class for launching, terminating, and tracking the state of processes. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llprocesslauncher.h" + +#include +#if LL_DARWIN || LL_LINUX +// not required or present on Win32 +#include +#endif + +LLProcessLauncher::LLProcessLauncher() +{ +#if LL_WINDOWS + mProcessHandle = 0; +#else + mProcessID = 0; +#endif +} + +LLProcessLauncher::~LLProcessLauncher() +{ + kill(); +} + +void LLProcessLauncher::setExecutable(const std::string &executable) +{ + mExecutable = executable; +} + +void LLProcessLauncher::setWorkingDirectory(const std::string &dir) +{ + mWorkingDir = dir; +} + +void LLProcessLauncher::clearArguments() +{ + mLaunchArguments.clear(); +} + +void LLProcessLauncher::addArgument(const std::string &arg) +{ + mLaunchArguments.push_back(arg); +} + +void LLProcessLauncher::addArgument(const char *arg) +{ + mLaunchArguments.push_back(std::string(arg)); +} + +#if LL_WINDOWS + +int LLProcessLauncher::launch(void) +{ + // If there was already a process associated with this object, kill it. + kill(); + orphan(); + + int result = 0; + + PROCESS_INFORMATION pinfo; + STARTUPINFOA sinfo; + memset(&sinfo, 0, sizeof(sinfo)); + + std::string args = "\"" + mExecutable + "\""; + for(int i = 0; i < (int)mLaunchArguments.size(); i++) + { + args += " "; + args += mLaunchArguments[i]; + } + LL_INFOS("Plugin") << "Executable: " << mExecutable << " arguments: " << args << LL_ENDL; + + // So retarded. Windows requires that the second parameter to CreateProcessA be a writable (non-const) string... + char *args2 = new char[args.size() + 1]; + strcpy(args2, args.c_str()); + + if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) ) + { + // TODO: do better than returning the OS-specific error code on failure... + result = GetLastError(); + if(result == 0) + { + // Make absolutely certain we return a non-zero value on failure. + result = -1; + } + } + else + { + // foo = pinfo.dwProcessId; // get your pid here if you want to use it later on + // CloseHandle(pinfo.hProcess); // stops leaks - nothing else + mProcessHandle = pinfo.hProcess; + CloseHandle(pinfo.hThread); // stops leaks - nothing else + } + + delete[] args2; + + return result; +} + +bool LLProcessLauncher::isRunning(void) +{ + if(mProcessHandle != 0) + { + DWORD waitresult = WaitForSingleObject(mProcessHandle, 0); + if(waitresult == WAIT_OBJECT_0) + { + // the process has completed. + mProcessHandle = 0; + } + } + + return (mProcessHandle != 0); +} +bool LLProcessLauncher::kill(void) +{ + bool result = true; + + if(mProcessHandle != 0) + { + TerminateProcess(mProcessHandle,0); + + if(isRunning()) + { + result = false; + } + } + + return result; +} + +void LLProcessLauncher::orphan(void) +{ + // Forget about the process + mProcessHandle = 0; +} + +// static +void LLProcessLauncher::reap(void) +{ + // No actions necessary on Windows. +} + +#else // Mac and linux + +#include +#include +#include + +static std::list sZombies; + +// Attempt to reap a process ID -- returns true if the process has exited and been reaped, false otherwise. +static bool reap_pid(pid_t pid) +{ + bool result = false; + + pid_t wait_result = ::waitpid(pid, NULL, WNOHANG); + if(wait_result == pid) + { + result = true; + } + else if(wait_result == -1) + { + if(errno == ECHILD) + { + // No such process -- this may mean we're ignoring SIGCHILD. + result = true; + } + } + + return result; +} + +int LLProcessLauncher::launch(void) +{ + // If there was already a process associated with this object, kill it. + kill(); + orphan(); + + int result = 0; + int current_wd = -1; + + // create an argv vector for the child process + const char ** fake_argv = new const char *[mLaunchArguments.size() + 2]; // 1 for the executable path, 1 for the NULL terminator + + int i = 0; + + // add the executable path + fake_argv[i++] = mExecutable.c_str(); + + // and any arguments + for(int j=0; j < mLaunchArguments.size(); j++) + fake_argv[i++] = mLaunchArguments[j].c_str(); + + // terminate with a null pointer + fake_argv[i] = NULL; + + if(!mWorkingDir.empty()) + { + // save the current working directory + current_wd = ::open(".", O_RDONLY); + + // and change to the one the child will be executed in + if (::chdir(mWorkingDir.c_str())) + { + // chdir failed + } + } + + // flush all buffers before the child inherits them + ::fflush(NULL); + + pid_t id = vfork(); + if(id == 0) + { + // child process + + ::execv(mExecutable.c_str(), (char * const *)fake_argv); + + // If we reach this point, the exec failed. + // Use _exit() instead of exit() per the vfork man page. + _exit(0); + } + + // parent process + + if(current_wd >= 0) + { + // restore the previous working directory + if (::fchdir(current_wd)) + { + // chdir failed + } + ::close(current_wd); + } + + delete[] fake_argv; + + mProcessID = id; + + // At this point, the child process will have been created (since that's how vfork works -- the child borrowed our execution context until it forked) + // If the process doesn't exist at this point, the exec failed. + if(!isRunning()) + { + result = -1; + } + + return result; +} + +bool LLProcessLauncher::isRunning(void) +{ + if(mProcessID != 0) + { + // Check whether the process has exited, and reap it if it has. + if(reap_pid(mProcessID)) + { + // the process has exited. + mProcessID = 0; + } + } + + return (mProcessID != 0); +} + +bool LLProcessLauncher::kill(void) +{ + bool result = true; + + if(mProcessID != 0) + { + // Try to kill the process. We'll do approximately the same thing whether the kill returns an error or not, so we ignore the result. + (void)::kill(mProcessID, SIGTERM); + + // This will have the side-effect of reaping the zombie if the process has exited. + if(isRunning()) + { + result = false; + } + } + + return result; +} + +void LLProcessLauncher::orphan(void) +{ + // Disassociate the process from this object + if(mProcessID != 0) + { + // We may still need to reap the process's zombie eventually + sZombies.push_back(mProcessID); + + mProcessID = 0; + } +} + +// static +void LLProcessLauncher::reap(void) +{ + // Attempt to real all saved process ID's. + + std::list::iterator iter = sZombies.begin(); + while(iter != sZombies.end()) + { + if(reap_pid(*iter)) + { + iter = sZombies.erase(iter); + } + else + { + iter++; + } + } +} + +#endif diff --git a/linden/indra/llcommon/llprocesslauncher.h b/linden/indra/llcommon/llprocesslauncher.h new file mode 100644 index 000000000..9833a1304 --- /dev/null +++ b/linden/indra/llcommon/llprocesslauncher.h @@ -0,0 +1,91 @@ +/** + * @file llprocesslauncher.h + * @brief Utility class for launching, terminating, and tracking the state of processes. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPROCESSLAUNCHER_H +#define LL_LLPROCESSLAUNCHER_H + +#if LL_WINDOWS +# define WIN32_LEAN_AND_MEAN +# include +#include +#endif + + +/* + LLProcessLauncher handles launching external processes with specified command line arguments. + It also keeps track of whether the process is still running, and can kill it if required. +*/ + +class LL_COMMON_API LLProcessLauncher +{ + LOG_CLASS(LLProcessLauncher); +public: + LLProcessLauncher(); + virtual ~LLProcessLauncher(); + + void setExecutable(const std::string &executable); + void setWorkingDirectory(const std::string &dir); + + void clearArguments(); + void addArgument(const std::string &arg); + void addArgument(const char *arg); + + int launch(void); + bool isRunning(void); + + // Attempt to kill the process -- returns true if the process is no longer running when it returns. + // Note that even if this returns false, the process may exit some time after it's called. + bool kill(void); + + // Use this if you want the external process to continue execution after the LLProcessLauncher instance controlling it is deleted. + // Normally, the destructor will attempt to kill the process and wait for termination. + // This should only be used if the viewer is about to exit -- otherwise, the child process will become a zombie after it exits. + void orphan(void); + + // This needs to be called periodically on Mac/Linux to clean up zombie processes. + static void reap(void); +private: + std::string mExecutable; + std::string mWorkingDir; + std::vector mLaunchArguments; + +#if LL_WINDOWS + HANDLE mProcessHandle; +#else + pid_t mProcessID; + +public: + pid_t getProcessID() const { return mProcessID; } +#endif +}; + +#endif // LL_LLPROCESSLAUNCHER_H diff --git a/linden/indra/llcommon/llqueuedthread.cpp b/linden/indra/llcommon/llqueuedthread.cpp index caf4c2a89..bee95be62 100644 --- a/linden/indra/llcommon/llqueuedthread.cpp +++ b/linden/indra/llcommon/llqueuedthread.cpp @@ -32,6 +32,7 @@ #include "linden_common.h" #include "llqueuedthread.h" #include "llstl.h" +#include "lltimer.h" //============================================================================ diff --git a/linden/indra/llcommon/llqueuedthread.h b/linden/indra/llcommon/llqueuedthread.h index aa7c6e4f6..e0e0f1bfe 100644 --- a/linden/indra/llcommon/llqueuedthread.h +++ b/linden/indra/llcommon/llqueuedthread.h @@ -47,7 +47,7 @@ // Note: ~LLQueuedThread is O(N) N=# of queued threads, assumed to be small // It is assumed that LLQueuedThreads are rarely created/destroyed. -class LLQueuedThread : public LLThread +class LL_COMMON_API LLQueuedThread : public LLThread { //------------------------------------------------------------------------ public: @@ -80,7 +80,7 @@ class LLQueuedThread : public LLThread //------------------------------------------------------------------------ public: - class QueuedRequest : public LLSimpleHashEntry + class LL_COMMON_API QueuedRequest : public LLSimpleHashEntry { friend class LLQueuedThread; diff --git a/linden/indra/llcommon/llrand.h b/linden/indra/llcommon/llrand.h index d12597bb5..73ea17956 100644 --- a/linden/indra/llcommon/llrand.h +++ b/linden/indra/llcommon/llrand.h @@ -65,32 +65,32 @@ /** *@brief Generate a float from [0, RAND_MAX). */ -S32 ll_rand(); +LL_COMMON_API S32 ll_rand(); /** *@brief Generate a float from [0, val) or (val, 0]. */ -S32 ll_rand(S32 val); +LL_COMMON_API S32 ll_rand(S32 val); /** *@brief Generate a float from [0, 1.0). */ -F32 ll_frand(); +LL_COMMON_API F32 ll_frand(); /** *@brief Generate a float from [0, val) or (val, 0]. */ -F32 ll_frand(F32 val); +LL_COMMON_API F32 ll_frand(F32 val); /** *@brief Generate a double from [0, 1.0). */ -F64 ll_drand(); +LL_COMMON_API F64 ll_drand(); /** *@brief Generate a double from [0, val) or (val, 0]. */ -F64 ll_drand(F64 val); +LL_COMMON_API F64 ll_drand(F64 val); /** * @brief typedefs for good boost lagged fibonacci. diff --git a/linden/indra/llcommon/llrun.h b/linden/indra/llcommon/llrun.h index 77b23d905..0f8d51d81 100644 --- a/linden/indra/llcommon/llrun.h +++ b/linden/indra/llcommon/llrun.h @@ -38,6 +38,8 @@ #include #include +#include "llpreprocessor.h" + class LLRunnable; /** @@ -48,7 +50,7 @@ class LLRunnable; * which are scheduled to run on a repeating or one time basis. * @see LLRunnable */ -class LLRunner +class LL_COMMON_API LLRunner { public: /** @@ -149,7 +151,7 @@ class LLRunner * something useful. * @see LLRunner */ -class LLRunnable +class LL_COMMON_API LLRunnable { public: LLRunnable(); diff --git a/linden/indra/llcommon/llscopedvolatileaprpool.h b/linden/indra/llcommon/llscopedvolatileaprpool.h new file mode 100644 index 000000000..724dc7f05 --- /dev/null +++ b/linden/indra/llcommon/llscopedvolatileaprpool.h @@ -0,0 +1,58 @@ +/** + * @file llscopedvolatileaprpool.h + * @brief Implementation of LLScopedVolatileAPRPool + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSCOPEDVOLATILEAPRPOOL_H +#define LL_LLSCOPEDVOLATILEAPRPOOL_H + +#include "llthread.h" + +//! Scoped volatile memory pool. +// +// As the AIVolatileAPRPool should never keep allocations very +// long, it's most common use is for allocations with a lifetime +// equal to it's scope. +// +// This is a convenience class that makes just a little easier to type. +// +class LLScopedVolatileAPRPool +{ +private: + AIVolatileAPRPool& mPool; + apr_pool_t* mScopedAPRpool; +public: + LLScopedVolatileAPRPool() : mPool(AIThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { } + ~LLScopedVolatileAPRPool() { mPool.clearVolatileAPRPool(); } + // Only use this to pass the pointer to a libapr-1 function that requires it. + operator apr_pool_t*() const { return mScopedAPRpool; } +}; + +#endif diff --git a/linden/indra/llcommon/llsd.cpp b/linden/indra/llcommon/llsd.cpp index 2cc94c291..be40bb634 100644 --- a/linden/indra/llcommon/llsd.cpp +++ b/linden/indra/llcommon/llsd.cpp @@ -75,7 +75,7 @@ class LLSD::Impl ///< This constructor is used for static objects and causes the // suppresses adjusting the debugging counters when they are // finally initialized. - + virtual ~Impl(); bool shared() const { return mUseCount > 1; } @@ -162,6 +162,7 @@ namespace virtual LLSD::Type type() const { return T; } + using LLSD::Impl::assign; virtual void assign(LLSD::Impl*& var, DataRef value) { if (shared()) { @@ -348,6 +349,10 @@ namespace virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + using LLSD::Impl::get; // Unhiding get(LLSD::Integer) + using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer) + using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer) + virtual bool has(const LLSD::String&) const; virtual LLSD get(const LLSD::String&) const; LLSD& insert(const LLSD::String& k, const LLSD& v); @@ -440,6 +445,11 @@ namespace virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } virtual int size() const; + + using LLSD::Impl::get; // Unhiding get(LLSD::Integer) + using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer) + using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer) + virtual LLSD get(LLSD::Integer) const; void set(LLSD::Integer, const LLSD&); LLSD& insert(LLSD::Integer, const LLSD&); diff --git a/linden/indra/llcommon/llsd.h b/linden/indra/llcommon/llsd.h index d2845a375..552bb5749 100644 --- a/linden/indra/llcommon/llsd.h +++ b/linden/indra/llcommon/llsd.h @@ -89,7 +89,7 @@ @nosubgrouping */ -class LLSD +class LL_COMMON_API LLSD { public: LLSD(); ///< initially Undefined @@ -387,7 +387,7 @@ struct llsd_select_string : public std::unary_function } }; -std::ostream& operator<<(std::ostream& s, const LLSD& llsd); +LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd); /** QUESTIONS & TO DOS - Would Binary be more convenient as usigned char* buffer semantics? diff --git a/linden/indra/llcommon/llsdserialize.h b/linden/indra/llcommon/llsdserialize.h index f7cd91bb7..a01b6dcd3 100644 --- a/linden/indra/llcommon/llsdserialize.h +++ b/linden/indra/llcommon/llsdserialize.h @@ -43,7 +43,7 @@ * @class LLSDParser * @brief Abstract base class for LLSD parsers. */ -class LLSDParser : public LLRefCount +class LL_COMMON_API LLSDParser : public LLRefCount { protected: /** @@ -220,7 +220,7 @@ class LLSDParser : public LLRefCount * @class LLSDNotationParser * @brief Parser which handles the original notation format for LLSD. */ -class LLSDNotationParser : public LLSDParser +class LL_COMMON_API LLSDNotationParser : public LLSDParser { protected: /** @@ -293,7 +293,7 @@ class LLSDNotationParser : public LLSDParser * @class LLSDXMLParser * @brief Parser which handles XML format LLSD. */ -class LLSDXMLParser : public LLSDParser +class LL_COMMON_API LLSDXMLParser : public LLSDParser { protected: /** @@ -341,7 +341,7 @@ class LLSDXMLParser : public LLSDParser * @class LLSDBinaryParser * @brief Parser which handles binary formatted LLSD. */ -class LLSDBinaryParser : public LLSDParser +class LL_COMMON_API LLSDBinaryParser : public LLSDParser { protected: /** @@ -406,7 +406,7 @@ class LLSDBinaryParser : public LLSDParser * @class LLSDFormatter * @brief Abstract base class for formatting LLSD. */ -class LLSDFormatter : public LLRefCount +class LL_COMMON_API LLSDFormatter : public LLRefCount { protected: /** @@ -478,7 +478,7 @@ class LLSDFormatter : public LLRefCount * @class LLSDNotationFormatter * @brief Formatter which outputs the original notation format for LLSD. */ -class LLSDNotationFormatter : public LLSDFormatter +class LL_COMMON_API LLSDNotationFormatter : public LLSDFormatter { protected: /** @@ -519,7 +519,7 @@ class LLSDNotationFormatter : public LLSDFormatter * @class LLSDXMLFormatter * @brief Formatter which outputs the LLSD as XML. */ -class LLSDXMLFormatter : public LLSDFormatter +class LL_COMMON_API LLSDXMLFormatter : public LLSDFormatter { protected: /** @@ -587,7 +587,7 @@ class LLSDXMLFormatter : public LLSDFormatter * Map: '{' + 4 byte integer size every(key + value) + '}'
* map keys are serialized as 'k' + 4 byte integer size + string */ -class LLSDBinaryFormatter : public LLSDFormatter +class LL_COMMON_API LLSDBinaryFormatter : public LLSDFormatter { protected: /** @@ -676,7 +676,7 @@ typedef LLSDOStreamer LLSDXMLStreamer; * @class LLSDSerialize * @brief Serializer / deserializer for the various LLSD formats */ -class LLSDSerialize +class LL_COMMON_API LLSDSerialize { public: enum ELLSD_Serialize diff --git a/linden/indra/llcommon/llsdserialize_xml.cpp b/linden/indra/llcommon/llsdserialize_xml.cpp index c12ca350d..33206b46d 100644 --- a/linden/indra/llcommon/llsdserialize_xml.cpp +++ b/linden/indra/llcommon/llsdserialize_xml.cpp @@ -562,7 +562,7 @@ void LLSDXMLParser::Impl::parsePart(const char* buf, int len) #ifdef XML_PARSER_PERFORMANCE_TESTS -extern U64 totalTime(); +extern LL_COMMON_API U64 totalTime(); U64 readElementTime = 0; U64 startElementTime = 0; U64 endElementTime = 0; diff --git a/linden/indra/llcommon/llsdutil.h b/linden/indra/llcommon/llsdutil.h index b67ad521e..4740a308e 100644 --- a/linden/indra/llcommon/llsdutil.h +++ b/linden/indra/llcommon/llsdutil.h @@ -68,28 +68,28 @@ LLSD ll_sd_from_color4(const LLColor4& c); LLColor4 ll_color4_from_sd(const LLSD& sd); // U32 -LLSD ll_sd_from_U32(const U32); -U32 ll_U32_from_sd(const LLSD& sd); +LL_COMMON_API LLSD ll_sd_from_U32(const U32); +LL_COMMON_API U32 ll_U32_from_sd(const LLSD& sd); // U64 -LLSD ll_sd_from_U64(const U64); -U64 ll_U64_from_sd(const LLSD& sd); +LL_COMMON_API LLSD ll_sd_from_U64(const U64); +LL_COMMON_API U64 ll_U64_from_sd(const LLSD& sd); // IP Address -LLSD ll_sd_from_ipaddr(const U32); -U32 ll_ipaddr_from_sd(const LLSD& sd); +LL_COMMON_API LLSD ll_sd_from_ipaddr(const U32); +LL_COMMON_API U32 ll_ipaddr_from_sd(const LLSD& sd); // Binary to string -LLSD ll_string_from_binary(const LLSD& sd); +LL_COMMON_API LLSD ll_string_from_binary(const LLSD& sd); //String to binary -LLSD ll_binary_from_string(const LLSD& sd); +LL_COMMON_API LLSD ll_binary_from_string(const LLSD& sd); // Serializes sd to static buffer and returns pointer, useful for gdb debugging. -char* ll_print_sd(const LLSD& sd); +LL_COMMON_API char* ll_print_sd(const LLSD& sd); // Serializes sd to static buffer and returns pointer, using "pretty printing" mode. -char* ll_pretty_print_sd(const LLSD& sd); +LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd); //compares the structure of an LLSD to a template LLSD and stores the //"valid" values in a 3rd LLSD. Default values @@ -98,7 +98,7 @@ char* ll_pretty_print_sd(const LLSD& sd); //Returns false if the test is of same type but values differ in type //Otherwise, returns true -BOOL compare_llsd_with_template( +LL_COMMON_API BOOL compare_llsd_with_template( const LLSD& llsd_to_test, const LLSD& template_llsd, LLSD& resultant_llsd); diff --git a/linden/indra/llcommon/llsecondlifeurls.h b/linden/indra/llcommon/llsecondlifeurls.h index 9c64b5766..e3932d0de 100644 --- a/linden/indra/llcommon/llsecondlifeurls.h +++ b/linden/indra/llcommon/llsecondlifeurls.h @@ -34,14 +34,14 @@ #define LL_LLSECONDLIFEURLS_H -extern const std::string AUCTION_URL; +LL_COMMON_API extern const std::string AUCTION_URL; -extern const std::string EVENTS_URL; +LL_COMMON_API extern const std::string EVENTS_URL; // Currency page -extern const std::string BUY_CURRENCY_URL; +LL_COMMON_API extern const std::string BUY_CURRENCY_URL; // Release Notes Redirect URL for Server and Viewer -extern const std::string RELEASE_NOTES_BASE_URL; +LL_COMMON_API extern const std::string RELEASE_NOTES_BASE_URL; #endif diff --git a/linden/indra/llcommon/llsimplehash.h b/linden/indra/llcommon/llsimplehash.h index 0ba2a3014..5df93b646 100644 --- a/linden/indra/llcommon/llsimplehash.h +++ b/linden/indra/llcommon/llsimplehash.h @@ -64,7 +64,7 @@ class LLSimpleHashEntry }; template -class LLSimpleHash +class LL_COMMON_API LLSimpleHash { public: LLSimpleHash() diff --git a/linden/indra/llcommon/llstat.h b/linden/indra/llcommon/llstat.h index 66521a31c..951091b47 100644 --- a/linden/indra/llcommon/llstat.h +++ b/linden/indra/llcommon/llstat.h @@ -52,7 +52,7 @@ class LLSD; // amounts of time with very low memory cost. // -class LLStatAccum +class LL_COMMON_API LLStatAccum { protected: LLStatAccum(bool use_frame_timer); @@ -109,7 +109,7 @@ class LLStatAccum F64 mLastSampleValue; }; -class LLStatMeasure : public LLStatAccum +class LL_COMMON_API LLStatMeasure : public LLStatAccum // gathers statistics about things that are measured // ex.: tempature, time dilation { @@ -124,7 +124,7 @@ class LLStatMeasure : public LLStatAccum }; -class LLStatRate : public LLStatAccum +class LL_COMMON_API LLStatRate : public LLStatAccum // gathers statistics about things that can be counted over time // ex.: LSL instructions executed, messages sent, simulator frames completed // renders it in terms of rate of thing per second @@ -140,7 +140,7 @@ class LLStatRate : public LLStatAccum }; -class LLStatTime : public LLStatAccum +class LL_COMMON_API LLStatTime : public LLStatAccum // gathers statistics about time spent in a block of code // measure average duration per second in the block { @@ -171,7 +171,7 @@ class LLStatTime : public LLStatAccum // Use this class on the stack to record statistics about an area of code -class LLPerfBlock +class LL_COMMON_API LLPerfBlock { public: struct StatEntry @@ -213,7 +213,7 @@ class LLPerfBlock // ---------------------------------------------------------------------------- -class LLPerfStats +class LL_COMMON_API LLPerfStats { public: LLPerfStats(const std::string& process_name = "unknown", S32 process_pid = 0); @@ -249,7 +249,7 @@ class LLPerfStats }; // ---------------------------------------------------------------------------- -class LLStat +class LL_COMMON_API LLStat { public: LLStat(const U32 num_bins = 32, BOOL use_frame_timer = FALSE); diff --git a/linden/indra/llcommon/llstreamtools.h b/linden/indra/llcommon/llstreamtools.h index a6dc4d51e..371fac57a 100644 --- a/linden/indra/llcommon/llstreamtools.h +++ b/linden/indra/llcommon/llstreamtools.h @@ -39,23 +39,23 @@ // unless specifed otherwise these all return input_stream.good() // skips spaces and tabs -bool skip_whitespace(std::istream& input_stream); +LL_COMMON_API bool skip_whitespace(std::istream& input_stream); // skips whitespace and newlines -bool skip_emptyspace(std::istream& input_stream); +LL_COMMON_API bool skip_emptyspace(std::istream& input_stream); // skips emptyspace and lines that start with a # -bool skip_comments_and_emptyspace(std::istream& input_stream); +LL_COMMON_API bool skip_comments_and_emptyspace(std::istream& input_stream); // skips to character after next newline -bool skip_line(std::istream& input_stream); +LL_COMMON_API bool skip_line(std::istream& input_stream); // skips to beginning of next non-emptyspace -bool skip_to_next_word(std::istream& input_stream); +LL_COMMON_API bool skip_to_next_word(std::istream& input_stream); // skips to character after the end of next keyword // a 'keyword' is defined as the first word on a line -bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream); +LL_COMMON_API bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream); // skip_to_start_of_next_keyword() is disabled -- might tickle corruption bug // in windows iostream @@ -65,14 +65,14 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream // characters are pulled out of input_stream and appended to output_string // returns result of input_stream.good() after characters are pulled -bool get_word(std::string& output_string, std::istream& input_stream); -bool get_line(std::string& output_string, std::istream& input_stream); +LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stream); +LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream); // characters are pulled out of input_stream (up to a max of 'n') // and appended to output_string // returns result of input_stream.good() after characters are pulled -bool get_word(std::string& output_string, std::istream& input_stream, int n); -bool get_line(std::string& output_string, std::istream& input_stream, int n); +LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stream, int n); +LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream, int n); // unget_line() is disabled -- might tickle corruption bug in windows iostream //// backs up the input_stream by line_size + 1 characters @@ -82,28 +82,28 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n); // removes the last char in 'line' if it matches 'c' // returns true if removed last char -bool remove_last_char(char c, std::string& line); +LL_COMMON_API bool remove_last_char(char c, std::string& line); // replaces escaped characters with the correct characters from left to right // "\\" ---> '\\' // "\n" ---> '\n' -void unescape_string(std::string& line); +LL_COMMON_API void unescape_string(std::string& line); // replaces unescaped characters with expanded equivalents from left to right // '\\' ---> "\\" // '\n' ---> "\n" -void escape_string(std::string& line); +LL_COMMON_API void escape_string(std::string& line); // replaces each '\n' character with ' ' -void replace_newlines_with_whitespace(std::string& line); +LL_COMMON_API void replace_newlines_with_whitespace(std::string& line); // erases any double-quote characters in line -void remove_double_quotes(std::string& line); +LL_COMMON_API void remove_double_quotes(std::string& line); // the 'keyword' is defined as the first word on a line // the 'value' is everything after the keyword on the same line // starting at the first non-whitespace and ending right before the newline -void get_keyword_and_value(std::string& keyword, +LL_COMMON_API void get_keyword_and_value(std::string& keyword, std::string& value, const std::string& line); @@ -111,13 +111,13 @@ void get_keyword_and_value(std::string& keyword, // read anymore or until we hit the count. Some istream // implimentations have a max that they will read. // Returns the number of bytes read. -std::streamsize fullread( +LL_COMMON_API std::streamsize fullread( std::istream& istr, char* buf, std::streamsize requested); -std::istream& operator>>(std::istream& str, const char *tocheck); +LL_COMMON_API std::istream& operator>>(std::istream& str, const char *tocheck); #endif diff --git a/linden/indra/llcommon/llstring.h b/linden/indra/llcommon/llstring.h index 3c6cd43ec..61767ace5 100644 --- a/linden/indra/llcommon/llstring.h +++ b/linden/indra/llcommon/llstring.h @@ -34,12 +34,14 @@ #define LL_LLSTRING_H #include +#include +#include +#include #if LL_LINUX || LL_SOLARIS #include #include #endif -#include "linden_common.h" #include @@ -144,7 +146,7 @@ struct char_traits }; #endif -class LLStringOps +class LL_COMMON_API LLStringOps { public: static char toUpper(char elem) { return toupper((unsigned char)elem); } @@ -179,8 +181,8 @@ class LLStringOps * @brief Return a string constructed from in without crashing if the * pointer is NULL. */ -std::string ll_safe_string(const char* in); -std::string ll_safe_string(const char* in, S32 maxlen); +std::string LL_COMMON_API ll_safe_string(const char* in); +std::string LL_COMMON_API ll_safe_string(const char* in, S32 maxlen); // Allowing assignments from non-strings into format_map_t is apparently @@ -209,7 +211,7 @@ class LLStringUtilBase ///////////////////////////////////////////////////////////////////////////////////////// // Static Utility functions that operate on std::strings - static std::basic_string null; + static std::basic_string const null; typedef std::map format_map_t; static S32 format(std::basic_string& s, const format_map_t& fmt_map); @@ -236,7 +238,8 @@ class LLStringUtilBase static void replaceTabsWithSpaces( std::basic_string& string, size_type spaces_per_tab ); static void replaceNonstandardASCII( std::basic_string& string, T replacement ); static void replaceChar( std::basic_string& string, T target, T replacement ); - + static void replaceString( std::basic_string& string, std::basic_string target, std::basic_string replacement ); + static BOOL containsNonprintable(const std::basic_string& string); static void stripNonprintable(std::basic_string& string); @@ -299,7 +302,7 @@ class LLStringUtilBase }; -template std::basic_string LLStringUtilBase::null; +template std::basic_string const LLStringUtilBase::null; typedef LLStringUtilBase LLStringUtil; typedef LLStringUtilBase LLWStringUtil; @@ -349,7 +352,7 @@ inline std::string chop_tail_copy( * @brief This translates a nybble stored as a hex value from 0-f back * to a nybble in the low order bits of the return byte. */ -U8 hex_as_nybble(char hex); +LL_COMMON_API U8 hex_as_nybble(char hex); /** * @brief read the contents of a file into a string. @@ -360,7 +363,7 @@ U8 hex_as_nybble(char hex); * @param filename The full name of the file to read. * @return Returns true on success. If false, str is unmodified. */ -bool _read_file_into_string(std::string& str, const std::string& filename); +LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename); /** * Unicode support @@ -369,52 +372,52 @@ bool _read_file_into_string(std::string& str, const std::string& filename); // Make the incoming string a utf8 string. Replaces any unknown glyph // with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest // of the data may not be recovered. -std::string rawstr_to_utf8(const std::string& raw); +LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw); // // We should never use UTF16 except when communicating with Win32! // typedef std::basic_string llutf16string; -LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); -LLWString utf16str_to_wstring(const llutf16string &utf16str); +LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); +LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str); -llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); -llutf16string wstring_to_utf16str(const LLWString &utf32str); +LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); +LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str); -llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len); -llutf16string utf8str_to_utf16str ( const std::string& utf8str ); +LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len); +LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str ); -LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); -LLWString utf8str_to_wstring(const std::string &utf8str); +LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); +LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str); // Same function, better name. JC inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); } // -S32 wchar_to_utf8chars(llwchar inchar, char* outchars); +LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars); -std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); -std::string wstring_to_utf8str(const LLWString &utf32str); +LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); +LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str); -std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); -std::string utf16str_to_utf8str(const llutf16string &utf16str); +LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); +LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str); // Length of this UTF32 string in bytes when transformed to UTF8 -S32 wstring_utf8_length(const LLWString& wstr); +LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); // Length in bytes of this wide char in a UTF8 string -S32 wchar_utf8_length(const llwchar wc); +LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); -std::string utf8str_tolower(const std::string& utf8str); +LL_COMMON_API std::string utf8str_tolower(const std::string& utf8str); // Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string. -S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len); +LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len); // Length in utf16string (UTF-16) of wlen wchars beginning at woffset. -S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen); +LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen); // Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.) -S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL); +LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL); /** * @brief Properly truncate a utf8 string to a maximum byte count. @@ -426,11 +429,11 @@ S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset * @param max_len The maximum number of bytes in the return value. * @return Returns a valid utf8 string with byte count <= max_len. */ -std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); +LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); -std::string utf8str_trim(const std::string& utf8str); +LL_COMMON_API std::string utf8str_trim(const std::string& utf8str); -S32 utf8str_compare_insensitive( +LL_COMMON_API S32 utf8str_compare_insensitive( const std::string& lhs, const std::string& rhs); @@ -441,17 +444,17 @@ S32 utf8str_compare_insensitive( * @param target_char The wchar to be replaced * @param replace_char The wchar which is written on replace */ -std::string utf8str_substChar( +LL_COMMON_API std::string utf8str_substChar( const std::string& utf8str, const llwchar target_char, const llwchar replace_char); -std::string utf8str_makeASCII(const std::string& utf8str); +LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str); // Hack - used for evil notecards. -std::string mbcsstring_makeASCII(const std::string& str); +LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); -std::string utf8str_removeCRLF(const std::string& utf8str); +LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); #if LL_WINDOWS @@ -476,14 +479,21 @@ std::string utf8str_removeCRLF(const std::string& utf8str); * formatted string. * */ -int safe_snprintf(char* str, size_t size, const char* format, ...); + +// Deal with the differeneces on Windows +namespace snprintf_hack +{ + LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...); +} + +using snprintf_hack::snprintf; /** * @brief Convert a wide string to std::string * * This replaces the unsafe W2A macro from ATL. */ -std::string ll_convert_wide_to_string(const wchar_t* in); +LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); //@} #endif // LL_WINDOWS @@ -506,7 +516,7 @@ namespace LLStringFn * with zero non-printable characters. * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. */ - void replace_nonprintable_in_ascii( + LL_COMMON_API void replace_nonprintable_in_ascii( std::basic_string& string, char replacement); @@ -520,7 +530,7 @@ namespace LLStringFn * with zero non-printable characters and zero pipe characters. * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. */ - void replace_nonprintable_and_pipe_in_ascii(std::basic_string& str, + LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string& str, char replacement); @@ -529,7 +539,7 @@ namespace LLStringFn * Returns a copy of the string with those characters removed. * Works with US ASCII and UTF-8 encoded strings. JC */ - std::string strip_invalid_xml(const std::string& input); + LL_COMMON_API std::string strip_invalid_xml(const std::string& input); /** @@ -540,7 +550,7 @@ namespace LLStringFn * with zero non-printable characters. * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. */ - void replace_ascii_controlchars( + LL_COMMON_API void replace_ascii_controlchars( std::basic_string& string, char replacement); } @@ -901,11 +911,22 @@ template void LLStringUtilBase::replaceChar( std::basic_string& string, T target, T replacement ) { size_type found_pos = 0; - for (found_pos = string.find(target, found_pos); - found_pos != std::basic_string::npos; - found_pos = string.find(target, found_pos)) + while( (found_pos = string.find(target, found_pos)) != std::basic_string::npos ) { string[found_pos] = replacement; + found_pos++; // avoid infinite defeat if target == replacement + } +} + +//static +template +void LLStringUtilBase::replaceString( std::basic_string& string, std::basic_string target, std::basic_string replacement ) +{ + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != std::basic_string::npos ) + { + string.replace( found_pos, target.length(), replacement ); + found_pos += replacement.length(); // avoid infinite defeat if replacement contains target } } diff --git a/linden/indra/llcommon/llstringtable.h b/linden/indra/llcommon/llstringtable.h index 449206327..b13b01639 100644 --- a/linden/indra/llcommon/llstringtable.h +++ b/linden/indra/llcommon/llstringtable.h @@ -56,7 +56,7 @@ const U32 MAX_STRINGS_LENGTH = 256; -class LLStringTableEntry +class LL_COMMON_API LLStringTableEntry { public: LLStringTableEntry(const char *str) @@ -81,7 +81,7 @@ class LLStringTableEntry S32 mCount; }; -class LLStringTable +class LL_COMMON_API LLStringTable { public: LLStringTable(int tablesize); @@ -115,7 +115,7 @@ class LLStringTable #endif }; -extern LLStringTable gStringTable; +extern LL_COMMON_API LLStringTable gStringTable; //============================================================================ @@ -125,7 +125,7 @@ extern LLStringTable gStringTable; typedef const std::string* LLStdStringHandle; -class LLStdStringTable +class LL_COMMON_API LLStdStringTable { public: LLStdStringTable(S32 tablesize = 0) diff --git a/linden/indra/llcommon/llsys.h b/linden/indra/llcommon/llsys.h index 03f48ca01..d5575b2e1 100644 --- a/linden/indra/llcommon/llsys.h +++ b/linden/indra/llcommon/llsys.h @@ -45,7 +45,7 @@ #include #include -class LLOSInfo +class LL_COMMON_API LLOSInfo { public: LLOSInfo(); @@ -70,7 +70,7 @@ class LLOSInfo }; -class LLCPUInfo +class LL_COMMON_API LLCPUInfo { public: LLCPUInfo(); @@ -99,7 +99,7 @@ class LLCPUInfo // // CLASS LLMemoryInfo -class LLMemoryInfo +class LL_COMMON_API LLMemoryInfo /*! @brief Class to query the memory subsystem @@ -123,15 +123,15 @@ class LLMemoryInfo }; -std::ostream& operator<<(std::ostream& s, const LLOSInfo& info); -std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info); -std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info); +LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLOSInfo& info); +LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info); +LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info); // gunzip srcfile into dstfile. Returns FALSE on error. -BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile); +LL_COMMON_API BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile); // gzip srcfile into dstfile. Returns FALSE on error. -BOOL gzip_file(const std::string& srcfile, const std::string& dstfile); +LL_COMMON_API BOOL gzip_file(const std::string& srcfile, const std::string& dstfile); -extern LLCPUInfo gSysCPU; +LL_COMMON_API extern LLCPUInfo gSysCPU; #endif // LL_LLSYS_H diff --git a/linden/indra/llcommon/llthread.cpp b/linden/indra/llcommon/llthread.cpp index 692d6c44f..5efaf0fe2 100644 --- a/linden/indra/llcommon/llthread.cpp +++ b/linden/indra/llcommon/llthread.cpp @@ -72,8 +72,8 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap // Set thread state to running threadp->mStatus = RUNNING; - // Create a thread local APRFile pool. - LLVolatileAPRPool::createLocalAPRFilePool(); + // Create a thread local data. + AIThreadLocalData::create(threadp); // Run the user supplied function threadp->run(); @@ -87,24 +87,14 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap } -LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : +LLThread::LLThread(std::string const& name) : mPaused(false), mName(name), mAPRThreadp(NULL), - mStatus(STOPPED) + mStatus(STOPPED), + mThreadLocalData(NULL) { - // Thread creation probably CAN be paranoid about APR being initialized, if necessary - if (poolp) - { - mIsLocalPool = false; - mAPRPoolp = poolp; - } - else - { - mIsLocalPool = true; - apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread - } - mRunCondition = new LLCondition(mAPRPoolp); + mRunCondition = new LLCondition; } @@ -147,24 +137,18 @@ void LLThread::shutdown() if (!isStopped()) { // This thread just wouldn't stop, even though we gave it time - llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl; + llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl; return; } mAPRThreadp = NULL; } delete mRunCondition; - - if (mIsLocalPool) - { - apr_pool_destroy(mAPRPoolp); - } } - void LLThread::start() { - apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp); + apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool()); // We won't bother joining apr_thread_detach(mAPRThreadp); @@ -265,38 +249,72 @@ void LLThread::wakeLocked() } } -//============================================================================ +#ifdef SHOW_ASSERT +// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread. +static apr_os_thread_t main_thread_id; +LL_COMMON_API bool is_main_thread(void) { return apr_os_thread_equal(main_thread_id, apr_os_thread_current()); } +#endif -LLMutex::LLMutex(apr_pool_t *poolp) : - mAPRMutexp(NULL) +// The thread private handle to access the AIThreadLocalData instance. +apr_threadkey_t* AIThreadLocalData::sThreadLocalDataKey; + +//static +void AIThreadLocalData::init(void) { - //if (poolp) - //{ - // mIsLocalPool = false; - // mAPRPoolp = poolp; - //} - //else + // Only do this once. + if (sThreadLocalDataKey) { - mIsLocalPool = true; - apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread + return; } - apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp); + + apr_status_t status = apr_threadkey_private_create(&sThreadLocalDataKey, &AIThreadLocalData::destroy, AIAPRRootPool::get()()); + ll_apr_assert_status(status); // Or out of memory, or system-imposed limit on the + // total number of keys per process {PTHREAD_KEYS_MAX} + // has been exceeded. + + // Create the thread-local data for the main thread (this function is called by the main thread). + AIThreadLocalData::create(NULL); + +#ifdef SHOW_ASSERT + // This function is called by the main thread. + main_thread_id = apr_os_thread_current(); +#endif } -LLMutex::~LLMutex() +// This is called once for every thread when the thread is destructed. +//static +void AIThreadLocalData::destroy(void* thread_local_data) { -#if _DEBUG - llassert(!isLocked()); // better not be locked! -#endif - apr_thread_mutex_destroy(mAPRMutexp); - mAPRMutexp = NULL; - if (mIsLocalPool) + delete reinterpret_cast(thread_local_data); +} + +//static +void AIThreadLocalData::create(LLThread* threadp) +{ + AIThreadLocalData* new_tld = new AIThreadLocalData; + if (threadp) { - apr_pool_destroy(mAPRPoolp); + threadp->mThreadLocalData = new_tld; } + apr_status_t status = apr_threadkey_private_set(new_tld, sThreadLocalDataKey); + llassert_always(status == APR_SUCCESS); } -bool LLMutex::isLocked() +//static +AIThreadLocalData& AIThreadLocalData::tldata(void) +{ + if (!sThreadLocalDataKey) + AIThreadLocalData::init(); + + void* data; + apr_status_t status = apr_threadkey_private_get(&data, sThreadLocalDataKey); + llassert_always(status == APR_SUCCESS); + return *static_cast(data); +} + +//============================================================================ + +bool LLMutexBase::isLocked() { if (!tryLock()) { @@ -308,12 +326,9 @@ bool LLMutex::isLocked() //============================================================================ -LLCondition::LLCondition(apr_pool_t *poolp) : - LLMutex(poolp) +LLCondition::LLCondition(AIAPRPool& parent) : LLMutex(parent) { - // base class (LLMutex) has already ensured that mAPRPoolp is set up. - - apr_thread_cond_create(&mAPRCondp, mAPRPoolp); + apr_thread_cond_create(&mAPRCondp, mPool()); } LLCondition::~LLCondition() @@ -349,7 +364,7 @@ void LLThreadSafeRefCount::initThreadSafeRefCount() { if (!sMutex) { - sMutex = new LLMutex(0); + sMutex = new LLMutex; } } diff --git a/linden/indra/llcommon/llthread.h b/linden/indra/llcommon/llthread.h index ed76a3b4f..275411f62 100644 --- a/linden/indra/llcommon/llthread.h +++ b/linden/indra/llcommon/llthread.h @@ -38,12 +38,33 @@ #include "llmemory.h" #include "apr_thread_cond.h" +#include "aiaprpool.h" + +#ifdef SHOW_ASSERT +extern bool is_main_thread(void); +#endif class LLThread; class LLMutex; class LLCondition; -class LLThread +class LL_COMMON_API AIThreadLocalData +{ +private: + static apr_threadkey_t* sThreadLocalDataKey; + +public: + // Thread-local memory pool. + AIAPRRootPool mRootPool; + AIVolatileAPRPool mVolatileAPRPool; + + static void init(void); + static void destroy(void* thread_local_data); + static void create(LLThread* pthread); + static AIThreadLocalData& tldata(void); +}; + +class LL_COMMON_API LLThread { public: typedef enum e_thread_status @@ -53,7 +74,7 @@ class LLThread QUITTING= 2 // Someone wants this thread to quit } EThreadStatus; - LLThread(const std::string& name, apr_pool_t *poolp = NULL); + LLThread(std::string const& name); virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state. virtual void shutdown(); // stops the thread @@ -82,7 +103,8 @@ class LLThread // this kicks off the apr thread void start(void); - apr_pool_t *getAPRPool() { return mAPRPoolp; } + // Return thread-local data for the current thread. + static AIThreadLocalData& tldata(void) { return AIThreadLocalData::tldata(); } private: bool mPaused; @@ -95,10 +117,11 @@ class LLThread LLCondition* mRunCondition; apr_thread_t *mAPRThreadp; - apr_pool_t *mAPRPoolp; - bool mIsLocalPool; EThreadStatus mStatus; + friend void AIThreadLocalData::create(LLThread* threadp); + AIThreadLocalData* mThreadLocalData; + void setQuitting(); // virtual function overridden by subclass -- this will be called when the thread runs @@ -125,12 +148,9 @@ class LLThread //============================================================================ -class LLMutex +class LL_COMMON_API LLMutexBase { public: - LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex - ~LLMutex(); - void lock() { apr_thread_mutex_lock(mAPRMutexp); } void unlock() { apr_thread_mutex_unlock(mAPRMutexp); } // Returns true if lock was obtained successfully. @@ -139,16 +159,60 @@ class LLMutex bool isLocked(); // non-blocking, but does do a lock/unlock so not free protected: - apr_thread_mutex_t *mAPRMutexp; - apr_pool_t *mAPRPoolp; - bool mIsLocalPool; + // mAPRMutexp is initialized and uninitialized in the derived class. + apr_thread_mutex_t* mAPRMutexp; +}; + +class LL_COMMON_API LLMutex : public LLMutexBase +{ +public: + LLMutex(AIAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent) + { + apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mPool()); + } + ~LLMutex() + { + llassert(!isLocked()); // better not be locked! + apr_thread_mutex_destroy(mAPRMutexp); + mAPRMutexp = NULL; + } + +protected: + AIAPRPool mPool; }; +#if APR_HAS_THREADS +// No need to use a root pool in this case. +typedef LLMutex LLMutexRootPool; +#else // APR_HAS_THREADS +class LL_COMMON_API LLMutexRootPool : public LLMutexBase +{ +public: + LLMutexRootPool(void) + { + apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mRootPool()); + } + ~LLMutexRootPool() + { +#if APR_POOL_DEBUG + // It is allowed to destruct root pools from a different thread. + mRootPool.grab_ownership(); +#endif + llassert(!isLocked()); // better not be locked! + apr_thread_mutex_destroy(mAPRMutexp); + mAPRMutexp = NULL; + } + +protected: + AIAPRRootPool mRootPool; +}; +#endif // APR_HAS_THREADS + // Actually a condition/mutex pair (since each condition needs to be associated with a mutex). -class LLCondition : public LLMutex +class LL_COMMON_API LLCondition : public LLMutex { public: - LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well. + LLCondition(AIAPRPool& parent = LLThread::tldata().mRootPool); ~LLCondition(); void wait(); // blocks @@ -159,10 +223,10 @@ class LLCondition : public LLMutex apr_thread_cond_t *mAPRCondp; }; -class LLMutexLock +class LL_COMMON_API LLMutexLock { public: - LLMutexLock(LLMutex* mutex) + LLMutexLock(LLMutexBase* mutex) { mMutex = mutex; mMutex->lock(); @@ -172,7 +236,102 @@ class LLMutexLock mMutex->unlock(); } private: - LLMutex* mMutex; + LLMutexBase* mMutex; +}; + +class AIRWLock +{ +public: + AIRWLock(AIAPRPool& parent = LLThread::tldata().mRootPool) : + mWriterWaitingMutex(parent), mNoHoldersCondition(parent), mHoldersCount(0), mWriterIsWaiting(false) { } + +private: + LLMutex mWriterWaitingMutex; //!< This mutex is locked while some writer is waiting for access. + LLCondition mNoHoldersCondition; //!< Access control for mHoldersCount. Condition true when there are no more holders. + int mHoldersCount; //!< Number of readers or -1 if a writer locked this object. + // This is volatile because we read it outside the critical area of mWriterWaitingMutex, at [1]. + // That means that other threads can change it while we are already in the (inlined) function rdlock. + // Without volatile, the following assembly would fail: + // register x = mWriterIsWaiting; + // /* some thread changes mWriterIsWaiting */ + // if (x ... + // However, because the function is fuzzy to begin with (we don't mind that this race + // condition exists) it would work fine without volatile. So, basically it's just here + // out of principle ;). -- Aleric + bool volatile mWriterIsWaiting; //!< True when there is a writer waiting for write access. + +public: + void rdlock(bool high_priority = false) + { + // Give a writer a higher priority (kinda fuzzy). + if (mWriterIsWaiting && !high_priority) // [1] If there is a writer interested, + { + mWriterWaitingMutex.lock(); // [2] then give it precedence and wait here. + // If we get here then the writer got it's access; mHoldersCount == -1. + mWriterWaitingMutex.unlock(); + } + mNoHoldersCondition.lock(); // [3] Get exclusive access to mHoldersCount. + while (mHoldersCount == -1) // [4] + { + mNoHoldersCondition.wait(); // [5] Wait till mHoldersCount is (or just was) 0. + } + ++mHoldersCount; // One more reader. + mNoHoldersCondition.unlock(); // Release lock on mHoldersCount. + } + void rdunlock(void) + { + mNoHoldersCondition.lock(); // Get exclusive access to mHoldersCount. + if (--mHoldersCount == 0) // Was this the last reader? + { + mNoHoldersCondition.signal(); // Tell waiting threads, see [5], [6] and [7]. + } + mNoHoldersCondition.unlock(); // Release lock on mHoldersCount. + } + void wrlock(void) + { + mWriterWaitingMutex.lock(); // Block new readers, see [2], + mWriterIsWaiting = true; // from this moment on, see [1]. + mNoHoldersCondition.lock(); // Get exclusive access to mHoldersCount. + while (mHoldersCount != 0) // Other readers or writers have this lock? + { + mNoHoldersCondition.wait(); // [6] Wait till mHoldersCount is (or just was) 0. + } + mWriterIsWaiting = false; // Stop checking the lock for new readers, see [1]. + mWriterWaitingMutex.unlock(); // Release blocked readers, they will still hang at [3]. + mHoldersCount = -1; // We are a writer now (will cause a hang at [5], see [4]). + mNoHoldersCondition.unlock(); // Release lock on mHolders (readers go from [3] to [5]). + } + void wrunlock(void) + { + mNoHoldersCondition.lock(); // Get exclusive access to mHoldersCount. + mHoldersCount = 0; // We have no writer anymore. + mNoHoldersCondition.signal(); // Tell waiting threads, see [5], [6] and [7]. + mNoHoldersCondition.unlock(); // Release lock on mHoldersCount. + } + void rd2wrlock(void) + { + mNoHoldersCondition.lock(); // Get exclusive access to mHoldersCount. Blocks new readers at [3]. + if (--mHoldersCount > 0) // Any other reads left? + { + mWriterWaitingMutex.lock(); // Block new readers, see [2], + mWriterIsWaiting = true; // from this moment on, see [1]. + while (mHoldersCount != 0) // Other readers (still) have this lock? + { + mNoHoldersCondition.wait(); // [7] Wait till mHoldersCount is (or just was) 0. + } + mWriterIsWaiting = false; // Stop checking the lock for new readers, see [1]. + mWriterWaitingMutex.unlock(); // Release blocked readers, they will still hang at [3]. + } + mHoldersCount = -1; // We are a writer now (will cause a hang at [5], see [4]). + mNoHoldersCondition.unlock(); // Release lock on mHolders (readers go from [3] to [5]). + } + void wr2rdlock(void) + { + mNoHoldersCondition.lock(); // Get exclusive access to mHoldersCount. + mHoldersCount = 1; // Turn writer into a reader. + mNoHoldersCondition.signal(); // Tell waiting readers, see [5]. + mNoHoldersCondition.unlock(); // Release lock on mHoldersCount. + } }; //============================================================================ @@ -187,12 +346,11 @@ void LLThread::unlockData() mRunCondition->unlock(); } - //============================================================================ // see llmemory.h for LLPointer<> definition -class LLThreadSafeRefCount +class LL_COMMON_API LLThreadSafeRefCount { public: static void initThreadSafeRefCount(); // creates sMutex @@ -244,7 +402,7 @@ class LLThreadSafeRefCount // Simple responder for self destructing callbacks // Pure virtual class -class LLResponder : public LLThreadSafeRefCount +class LL_COMMON_API LLResponder : public LLThreadSafeRefCount { protected: virtual ~LLResponder(); diff --git a/linden/indra/llcommon/lltimer.cpp b/linden/indra/llcommon/lltimer.cpp index fa6efaf38..2d283ecaa 100644 --- a/linden/indra/llcommon/lltimer.cpp +++ b/linden/indra/llcommon/lltimer.cpp @@ -33,6 +33,7 @@ #include "linden_common.h" #include "lltimer.h" +#include "timing.h" // totalTime prototype. #include "u64.h" @@ -51,9 +52,6 @@ // // Locally used constants // -const U32 SEC_PER_DAY = 86400; -const F64 SEC_TO_MICROSEC = 1000000.f; -const U64 SEC_TO_MICROSEC_U64 = 1000000; const F64 USEC_TO_SEC_F64 = 0.000001; @@ -527,6 +525,34 @@ struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time) } +struct tm* utc_to_offset_time(time_t utc_time, S32 offset, BOOL DST) +{ + if (DST) + { + //Subtract one then + offset--; + } + + // We subtract off the PST/PDT offset _before_ getting + // "UTC" time, because this will handle wrapping around + // for 5 AM UTC -> 10 PM PDT of the previous day. + utc_time -= offset * MIN_PER_HOUR * SEC_PER_MIN; + + // Internal buffer to PST/PDT (see above) + struct tm* internal_time = gmtime(&utc_time); + + /* + // Don't do this, this won't correctly tell you if daylight savings is active in CA or not. + if (pacific_daylight_time) + { + internal_time->tm_isdst = 1; + } + */ + + return internal_time; +} + + void microsecondsToTimecodeString(U64 current_time, std::string& tcstring) { U64 hours; diff --git a/linden/indra/llcommon/lltimer.h b/linden/indra/llcommon/lltimer.h index e2cf1c768..8590328c7 100644 --- a/linden/indra/llcommon/lltimer.h +++ b/linden/indra/llcommon/lltimer.h @@ -39,6 +39,7 @@ #include #include "stdtypes.h" +#include "llpreprocessor.h" #include "lldate.h" #include @@ -54,7 +55,7 @@ const U32 USEC_PER_HOUR = USEC_PER_MIN * MIN_PER_HOUR; const U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR; const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC; -class LLTimer +class LL_COMMON_API LLTimer { public: static LLTimer *sTimer; // global timer @@ -113,17 +114,17 @@ class LLTimer // // Various functions for initializing/accessing clock and timing stuff. Don't use these without REALLY knowing how they work. // -U64 get_clock_count(); -F64 calc_clock_frequency(U32 msecs); -void update_clock_frequencies(); +LL_COMMON_API U64 get_clock_count(); +LL_COMMON_API F64 calc_clock_frequency(U32 msecs); +LL_COMMON_API void update_clock_frequencies(); // Sleep for milliseconds -void ms_sleep(U32 ms); -U32 micro_sleep(U64 us, U32 max_yields = 0xFFFFFFFF); +LL_COMMON_API void ms_sleep(U32 ms); +LL_COMMON_API U32 micro_sleep(U64 us, U32 max_yields = 0xFFFFFFFF); // Returns the correct UTC time in seconds, like time(NULL). // Useful on the viewer, which may have its local clock set wrong. -time_t time_corrected(); +LL_COMMON_API time_t time_corrected(); static inline time_t time_min() { @@ -154,24 +155,25 @@ static inline time_t time_max() } // Correction factor used by time_corrected() above. -extern S32 gUTCOffset; +LL_COMMON_API extern S32 gUTCOffset; // Is the current computer (in its current time zone) // observing daylight savings time? -BOOL is_daylight_savings(); +LL_COMMON_API BOOL is_daylight_savings(); // Converts internal "struct tm" time buffer to Pacific Standard/Daylight Time // Usage: // S32 utc_time; // utc_time = time_corrected(); // struct tm* internal_time = utc_to_pacific_time(utc_time, gDaylight); -struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time); +LL_COMMON_API struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time); +LL_COMMON_API struct tm* utc_to_offset_time(time_t utc_time, S32 offset, BOOL DST); -void microsecondsToTimecodeString(U64 current_time, std::string& tcstring); -void secondsToTimecodeString(F32 current_time, std::string& tcstring); +LL_COMMON_API void microsecondsToTimecodeString(U64 current_time, std::string& tcstring); +LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstring); // class for scheduling a function to be called at a given frequency (approximate, inprecise) -class LLEventTimer +class LL_COMMON_API LLEventTimer { public: LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds diff --git a/linden/indra/llcommon/lluri.h b/linden/indra/llcommon/lluri.h index 156d80b97..57bbedf42 100644 --- a/linden/indra/llcommon/lluri.h +++ b/linden/indra/llcommon/lluri.h @@ -47,7 +47,7 @@ class LLApp; * See: http://www.ietf.org/rfc/rfc3986.txt * */ -class LLURI +class LL_COMMON_API LLURI { public: LLURI(); @@ -189,6 +189,6 @@ class LLURI }; // this operator required for tut -bool operator!=(const LLURI& first, const LLURI& second); +LL_COMMON_API bool operator!=(const LLURI& first, const LLURI& second); #endif // LL_LLURI_H diff --git a/linden/indra/llcommon/lluuid.h b/linden/indra/llcommon/lluuid.h index 4b32138a0..c78fb1201 100644 --- a/linden/indra/llcommon/lluuid.h +++ b/linden/indra/llcommon/lluuid.h @@ -35,6 +35,7 @@ #include #include #include "stdtypes.h" +#include "llpreprocessor.h" const S32 UUID_BYTES = 16; const S32 UUID_WORDS = 4; @@ -47,7 +48,7 @@ struct uuid_time_t { U32 low; }; -class LLUUID +class LL_COMMON_API LLUUID { public: // @@ -106,8 +107,8 @@ class LLUUID LLUUID combine(const LLUUID& other) const; void combine(const LLUUID& other, LLUUID& result) const; - friend std::ostream& operator<<(std::ostream& s, const LLUUID &uuid); - friend std::istream& operator>>(std::istream& s, LLUUID &uuid); + friend LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLUUID &uuid); + friend LL_COMMON_API std::istream& operator>>(std::istream& s, LLUUID &uuid); void toString(char *out) const; // Does not allocate memory, needs 36 characters (including \0) void toString(std::string& out) const; @@ -323,7 +324,7 @@ typedef std::set uuid_list_t; */ typedef LLUUID LLAssetID; -class LLTransactionID : public LLUUID +class LL_COMMON_API LLTransactionID : public LLUUID { public: LLTransactionID() : LLUUID() { } diff --git a/linden/indra/llcommon/llworkerthread.cpp b/linden/indra/llcommon/llworkerthread.cpp index 8195e1cc8..e238a89b0 100644 --- a/linden/indra/llcommon/llworkerthread.cpp +++ b/linden/indra/llcommon/llworkerthread.cpp @@ -43,7 +43,7 @@ LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) : LLQueuedThread(name, threaded) { - mDeleteMutex = new LLMutex(NULL); + mDeleteMutex = new LLMutex; } LLWorkerThread::~LLWorkerThread() @@ -183,7 +183,6 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na : mWorkerThread(workerthread), mWorkerClassName(name), mRequestHandle(LLWorkerThread::nullHandle()), - mMutex(NULL), mWorkFlags(0) { if (!mWorkerThread) diff --git a/linden/indra/llcommon/llworkerthread.h b/linden/indra/llcommon/llworkerthread.h index 708d81236..8e0dd8a2e 100644 --- a/linden/indra/llcommon/llworkerthread.h +++ b/linden/indra/llcommon/llworkerthread.h @@ -50,7 +50,7 @@ class LLWorkerClass; // Note: ~LLWorkerThread is O(N) N=# of worker threads, assumed to be small // It is assumed that LLWorkerThreads are rarely created/destroyed. -class LLWorkerThread : public LLQueuedThread +class LL_COMMON_API LLWorkerThread : public LLQueuedThread { friend class LLWorkerClass; public: @@ -114,7 +114,7 @@ class LLWorkerThread : public LLQueuedThread // Only one background task can be active at a time (per instance). // i.e. don't call addWork() if haveWork() returns true -class LLWorkerClass +class LL_COMMON_API LLWorkerClass { friend class LLWorkerThread; friend class LLWorkerThread::WorkRequest; @@ -194,7 +194,7 @@ class LLWorkerClass U32 mRequestPriority; // last priority set private: - LLMutex mMutex; + LLMutexRootPool mMutex; // Use LLMutexRootPool since this object is created and destructed by multiple threads. LLAtomicU32 mWorkFlags; }; diff --git a/linden/indra/llcommon/metaclass.h b/linden/indra/llcommon/metaclass.h index cc10f1675..f38bcd2d5 100644 --- a/linden/indra/llcommon/metaclass.h +++ b/linden/indra/llcommon/metaclass.h @@ -43,7 +43,7 @@ class LLReflective; class LLMetaProperty; class LLMetaMethod; -class LLMetaClass +class LL_COMMON_API LLMetaClass { public: diff --git a/linden/indra/llcommon/metaproperty.h b/linden/indra/llcommon/metaproperty.h index e5ac35907..6c016c56d 100644 --- a/linden/indra/llcommon/metaproperty.h +++ b/linden/indra/llcommon/metaproperty.h @@ -41,7 +41,7 @@ class LLMetaClass; class LLReflective; -class LLMetaProperty +class LL_COMMON_API LLMetaProperty { public: LLMetaProperty(const std::string& name, const LLMetaClass& object_class); diff --git a/linden/indra/llcommon/reflective.h b/linden/indra/llcommon/reflective.h index e2c18ebc6..a13537681 100644 --- a/linden/indra/llcommon/reflective.h +++ b/linden/indra/llcommon/reflective.h @@ -36,7 +36,7 @@ #define LL_REFLECTIVE_H class LLMetaClass; -class LLReflective +class LL_COMMON_API LLReflective { public: LLReflective(); diff --git a/linden/indra/llcommon/timing.h b/linden/indra/llcommon/timing.h index 2b9f60ada..cfc637eb6 100644 --- a/linden/indra/llcommon/timing.h +++ b/linden/indra/llcommon/timing.h @@ -44,6 +44,6 @@ const U64 SEC_TO_MICROSEC_U64 = 1000000; const U32 SEC_PER_DAY = 86400; // This is just a stub, implementation in lltimer.cpp. This file will be deprecated in the future. -U64 totalTime(); // Returns current system time in microseconds +LL_COMMON_API U64 totalTime(); // Returns current system time in microseconds #endif diff --git a/linden/indra/llcommon/u64.h b/linden/indra/llcommon/u64.h index 09a6b3e18..eb51131e9 100644 --- a/linden/indra/llcommon/u64.h +++ b/linden/indra/llcommon/u64.h @@ -39,14 +39,14 @@ * @param str The string to parse. * @return Returns the first U64 value found in the string or 0 on failure. */ -U64 str_to_U64(const std::string& str); +LL_COMMON_API U64 str_to_U64(const std::string& str); /** * @brief Given a U64 value, return a printable representation. * @param value The U64 to turn into a printable character array. * @return Returns the result string. */ -std::string U64_to_str(U64 value); +LL_COMMON_API std::string U64_to_str(U64 value); /** * @brief Given a U64 value, return a printable representation. @@ -65,16 +65,16 @@ std::string U64_to_str(U64 value); * @param result_size The size of the buffer allocated. Use U64_BUF. * @return Returns the result pointer. */ -char* U64_to_str(U64 value, char* result, S32 result_size); +LL_COMMON_API char* U64_to_str(U64 value, char* result, S32 result_size); /** * @brief Convert a U64 to the closest F64 value. */ -F64 U64_to_F64(const U64 value); +LL_COMMON_API F64 U64_to_F64(const U64 value); /** * @brief Helper function to wrap strtoull() which is not available on windows. */ -U64 llstrtou64(const char* str, char** end, S32 base); +LL_COMMON_API U64 llstrtou64(const char* str, char** end, S32 base); #endif diff --git a/linden/indra/llcrashlogger/llcrashlogger.cpp b/linden/indra/llcrashlogger/llcrashlogger.cpp index d25be5580..b6afbc6ca 100755 --- a/linden/indra/llcrashlogger/llcrashlogger.cpp +++ b/linden/indra/llcrashlogger/llcrashlogger.cpp @@ -387,8 +387,7 @@ bool LLCrashLogger::init() return false; } - gServicePump = new LLPumpIO(gAPRPoolp); - gServicePump->prime(gAPRPoolp); + gServicePump = new LLPumpIO; LLHTTPClient::setPump(*gServicePump); //If we've opened the crash logger, assume we can delete the marker file if it exists diff --git a/linden/indra/llimage/llimage.cpp b/linden/indra/llimage/llimage.cpp index 776c481f0..e9337509f 100644 --- a/linden/indra/llimage/llimage.cpp +++ b/linden/indra/llimage/llimage.cpp @@ -57,7 +57,7 @@ LLMutex* LLImage::sMutex = NULL; //static void LLImage::initClass(const bool& useDSO) { - sMutex = new LLMutex(NULL); + sMutex = new LLMutex; if (useDSO) { LLImageJ2C::openDSO(); diff --git a/linden/indra/llimage/llimagej2c.cpp b/linden/indra/llimage/llimagej2c.cpp index b99ebff98..9e88bcd66 100644 --- a/linden/indra/llimage/llimagej2c.cpp +++ b/linden/indra/llimage/llimagej2c.cpp @@ -46,7 +46,7 @@ typedef const char* (*EngineInfoLLImageJ2CFunction)(); CreateLLImageJ2CFunction j2cimpl_create_func; DestroyLLImageJ2CFunction j2cimpl_destroy_func; EngineInfoLLImageJ2CFunction j2cimpl_engineinfo_func; -apr_pool_t *j2cimpl_dso_memory_pool; +AIAPRPool j2cimpl_dso_memory_pool; apr_dso_handle_t *j2cimpl_dso_handle; //Declare the prototype for theses functions here, their functionality @@ -81,13 +81,12 @@ void LLImageJ2C::openDSO() gDirUtilp->getExecutableDir()); j2cimpl_dso_handle = NULL; - j2cimpl_dso_memory_pool = NULL; + j2cimpl_dso_memory_pool.create(); //attempt to load the shared library - apr_pool_create(&j2cimpl_dso_memory_pool, NULL); rv = apr_dso_load(&j2cimpl_dso_handle, dso_path.c_str(), - j2cimpl_dso_memory_pool); + j2cimpl_dso_memory_pool()); //now, check for success if ( rv == APR_SUCCESS ) @@ -151,11 +150,7 @@ void LLImageJ2C::openDSO() j2cimpl_dso_handle = NULL; } - if ( j2cimpl_dso_memory_pool ) - { - apr_pool_destroy(j2cimpl_dso_memory_pool); - j2cimpl_dso_memory_pool = NULL; - } + j2cimpl_dso_memory_pool.destroy(); } } @@ -163,7 +158,7 @@ void LLImageJ2C::openDSO() void LLImageJ2C::closeDSO() { if ( j2cimpl_dso_handle ) apr_dso_unload(j2cimpl_dso_handle); - if (j2cimpl_dso_memory_pool) apr_pool_destroy(j2cimpl_dso_memory_pool); + j2cimpl_dso_memory_pool.destroy(); } //static diff --git a/linden/indra/llimage/llimageworker.cpp b/linden/indra/llimage/llimageworker.cpp index 558a968bd..dc989e53f 100644 --- a/linden/indra/llimage/llimageworker.cpp +++ b/linden/indra/llimage/llimageworker.cpp @@ -41,14 +41,13 @@ LLImageDecodeThread::LLImageDecodeThread(bool threaded) : LLQueuedThread("imagedecode", threaded) { - mCreationMutex = new LLMutex(getAPRPool()); } // MAIN THREAD // virtual S32 LLImageDecodeThread::update(U32 max_time_ms) { - LLMutexLock lock(mCreationMutex); + LLMutexLock lock(&mCreationMutex); for (creation_list_t::iterator iter = mCreationList.begin(); iter != mCreationList.end(); ++iter) { @@ -71,7 +70,7 @@ S32 LLImageDecodeThread::update(U32 max_time_ms) LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image, U32 priority, S32 discard, BOOL needs_aux, Responder* responder) { - LLMutexLock lock(mCreationMutex); + LLMutexLock lock(&mCreationMutex); handle_t handle = generateHandle(); mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder)); return handle; @@ -81,7 +80,7 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* // Returns the size of the mutex guarded list as an indication of sanity S32 LLImageDecodeThread::tut_size() { - LLMutexLock lock(mCreationMutex); + LLMutexLock lock(&mCreationMutex); S32 res = mCreationList.size(); return res; } diff --git a/linden/indra/llimage/llimageworker.h b/linden/indra/llimage/llimageworker.h index 026020648..fa2a8fa75 100644 --- a/linden/indra/llimage/llimageworker.h +++ b/linden/indra/llimage/llimageworker.h @@ -101,7 +101,7 @@ class LLImageDecodeThread : public LLQueuedThread }; typedef std::list creation_list_t; creation_list_t mCreationList; - LLMutex* mCreationMutex; + LLMutex mCreationMutex; }; #endif diff --git a/linden/indra/llinventory/llparcel.cpp b/linden/indra/llinventory/llparcel.cpp index 9c27476b0..39605ebfd 100644 --- a/linden/indra/llinventory/llparcel.cpp +++ b/linden/indra/llinventory/llparcel.cpp @@ -199,6 +199,12 @@ void LLParcel::init(const LLUUID &owner_id, mObscureMusic = 1; mMediaWidth = 0; mMediaHeight = 0; + setMediaCurrentURL(LLStringUtil::null); + mMediaURLFilterEnable = FALSE; + mMediaURLFilterList = LLSD::emptyArray(); + mMediaAllowNavigate = TRUE; + mMediaURLTimeout = 0.0f; + mMediaPreventCameraZoom = FALSE; mGroupID.setNull(); @@ -300,11 +306,11 @@ void LLParcel::setMediaType(const std::string& type) mMediaType = type; mMediaType = rawstr_to_utf8(mMediaType); - // This code attempts to preserve legacy movie functioning - if(mMediaType.empty() && ! mMediaURL.empty()) - { - setMediaType(std::string("video/vnd.secondlife.qt.legacy")); - } +// // This legacy code prevents any media different from video from working on OpenSim +// if(mMediaType.empty() && ! mMediaURL.empty()) +// { +// setMediaType(std::string("video/vnd.secondlife.qt.legacy")); +// } } void LLParcel::setMediaWidth(S32 width) { @@ -314,6 +320,56 @@ void LLParcel::setMediaHeight(S32 height) { mMediaHeight = height; } + +void LLParcel::setMediaCurrentURL(const std::string& url) +{ + mMediaCurrentURL = url; + // The escaping here must match the escaping in the database + // abstraction layer if it's ever added. + // This should really filter the url in some way. Other than + // simply requiring non-printable. + LLStringFn::replace_nonprintable_in_ascii(mMediaCurrentURL, LL_UNKNOWN_CHAR); + +} + +void LLParcel::setMediaURLResetTimer(F32 time) +{ + mMediaResetTimer.start(); + mMediaResetTimer.setTimerExpirySec(time); +} + +void LLParcel::setMediaURLFilterList(LLSD list) +{ + // sanity check LLSD + // must be array of strings + if (!list.isArray()) + { + return; + } + + for (S32 i = 0; i < list.size(); i++) + { + if (!list[i].isString()) + return; + } + + // can't be too big + const S32 MAX_SIZE = 50; + if (list.size() > MAX_SIZE) + { + LLSD new_list = LLSD::emptyArray(); + + for (S32 i = 0; i < llmin(list.size(), MAX_SIZE); i++) + { + new_list.append(list[i]); + } + + list = new_list; + } + + mMediaURLFilterList = list; +} + // virtual void LLParcel::setLocalID(S32 local_id) { @@ -568,6 +624,34 @@ BOOL LLParcel::importAccessEntry(std::istream& input_stream, LLAccessEntry* entr return input_stream.good(); } +BOOL LLParcel::importMediaURLFilter(std::istream& input_stream, std::string& url) +{ + skip_to_end_of_next_keyword("{", input_stream); + + while(input_stream.good()) + { + skip_comments_and_emptyspace(input_stream); + std::string line, keyword, value; + get_line(line, input_stream, MAX_STRING); + get_keyword_and_value(keyword, value, line); + + if ("}" == keyword) + { + break; + } + else if ("url" == keyword) + { + url = value; + } + else + { + llwarns << "Unknown keyword in parcel media url filter section: <" + << keyword << ">" << llendl; + } + } + return input_stream.good(); +} + // Assumes we are in a block "ParcelData" void LLParcel::packMessage(LLMessageSystem* msg) { @@ -606,9 +690,15 @@ void LLParcel::packMessage(LLSD& msg) msg["media_height"] = getMediaHeight(); msg["auto_scale"] = getMediaAutoScale(); msg["media_loop"] = getMediaLoop(); + msg["media_current_url"] = getMediaCurrentURL(); msg["obscure_media"] = getObscureMedia(); msg["obscure_music"] = getObscureMusic(); msg["media_id"] = getMediaID(); + msg["media_allow_navigate"] = getMediaAllowNavigate(); + msg["media_prevent_camera_zoom"] = getMediaPreventCameraZoom(); + msg["media_url_timeout"] = getMediaURLTimeout(); + msg["media_url_filter_enable"] = getMediaURLFilterEnable(); + msg["media_url_filter_list"] = getMediaURLFilterList(); msg["group_id"] = getGroupID(); msg["pass_price"] = mPassPrice; msg["pass_hours"] = mPassHours; @@ -672,12 +762,28 @@ void LLParcel::unpackMessage(LLMessageSystem* msg) } else { - setMediaType(std::string("video/vnd.secondlife.qt.legacy")); + setMediaType(std::string("")); //having mMediaType empty causes autodetect, + // thats what we want -- AW setMediaDesc(std::string("No Description available without Server Upgrade")); mMediaLoop = true; mObscureMedia = true; mObscureMusic = true; } + + if(msg->getNumberOfBlocks("MediaLinkSharing") > 0) + { + msg->getString("MediaLinkSharing", "MediaCurrentURL", buffer); + setMediaCurrentURL(buffer); + msg->getU8 ( "MediaLinkSharing", "MediaAllowNavigate", mMediaAllowNavigate ); + msg->getU8 ( "MediaLinkSharing", "MediaURLFilterEnable", mMediaURLFilterEnable ); + msg->getU8 ( "MediaLinkSharing", "MediaPreventCameraZoom", mMediaPreventCameraZoom ); + msg->getF32( "MediaLinkSharing", "MediaURLTimeout", mMediaURLTimeout); + } + else + { + setMediaCurrentURL(LLStringUtil::null); + } + } void LLParcel::packAccessEntries(LLMessageSystem* msg, @@ -994,6 +1100,20 @@ BOOL LLParcel::isSaleTimerExpired(const U64& time) return expired; } +BOOL LLParcel::isMediaResetTimerExpired(const U64& time) +{ + if (mMediaResetTimer.getStarted() == FALSE) + { + return FALSE; + } + BOOL expired = mMediaResetTimer.checkExpirationAndReset(0.0); + if (expired) + { + mMediaResetTimer.stop(); + } + return expired; +} + void LLParcel::startSale(const LLUUID& buyer_id, BOOL is_buyer_group) { @@ -1117,6 +1237,12 @@ void LLParcel::clearParcel() mObscureMusic = 1; mMediaWidth = 0; mMediaHeight = 0; + setMediaCurrentURL(LLStringUtil::null); + setMediaURLFilterList(LLSD::emptyArray()); + setMediaURLFilterEnable(FALSE); + setMediaAllowNavigate(TRUE); + setMediaPreventCameraZoom(FALSE); + setMediaURLTimeout(0.0f); setMusicURL(LLStringUtil::null); setInEscrow(FALSE); setAuthorizedBuyerID(LLUUID::null); diff --git a/linden/indra/llinventory/llparcel.h b/linden/indra/llinventory/llparcel.h index 6f5ae87eb..8faa673c3 100644 --- a/linden/indra/llinventory/llparcel.h +++ b/linden/indra/llinventory/llparcel.h @@ -39,7 +39,7 @@ #include "llparcelflags.h" #include "llpermissions.h" #include "v3math.h" - +#include "lltimer.h" // Grid out of which parcels taken is stepped every 4 meters. const F32 PARCEL_GRID_STEP_METERS = 4.f; @@ -247,6 +247,14 @@ class LLParcel void setObscureMusic( U8 flagIn ) { mObscureMusic = flagIn; } void setMediaWidth(S32 width); void setMediaHeight(S32 height); + void setMediaCurrentURL(const std::string& url); + void setMediaURLFilterEnable(U8 enable) { mMediaURLFilterEnable = enable; } + void setMediaURLFilterList(LLSD list); + void setMediaAllowNavigate(U8 enable) { mMediaAllowNavigate = enable; } + void setMediaURLTimeout(F32 timeout) { mMediaURLTimeout = timeout; } + void setMediaPreventCameraZoom(U8 enable) { mMediaPreventCameraZoom = enable; } + + void setMediaURLResetTimer(F32 time); virtual void setLocalID(S32 local_id); // blow away all the extra crap lurking in parcels, including urls, access lists, etc @@ -300,6 +308,7 @@ class LLParcel // BOOL importStream(std::istream& input_stream); BOOL importAccessEntry(std::istream& input_stream, LLAccessEntry* entry); // BOOL exportStream(std::ostream& output_stream); + BOOL importMediaURLFilter(std::istream& input_stream, std::string& url); void packMessage(LLMessageSystem* msg); void packMessage(LLSD& msg); @@ -341,8 +350,15 @@ class LLParcel S32 getMediaHeight() const { return mMediaHeight; } U8 getMediaAutoScale() const { return mMediaAutoScale; } U8 getMediaLoop() const { return mMediaLoop; } + const std::string& getMediaCurrentURL() const { return mMediaCurrentURL; } U8 getObscureMedia() const { return mObscureMedia; } U8 getObscureMusic() const { return mObscureMusic; } + U8 getMediaURLFilterEnable() const { return mMediaURLFilterEnable; } + LLSD getMediaURLFilterList() const { return mMediaURLFilterList; } + U8 getMediaAllowNavigate() const { return mMediaAllowNavigate; } + F32 getMediaURLTimeout() const { return mMediaURLTimeout; } + U8 getMediaPreventCameraZoom() const { return mMediaPreventCameraZoom; } + S32 getLocalID() const { return mLocalID; } const LLUUID& getOwnerID() const { return mOwnerID; } const LLUUID& getGroupID() const { return mGroupID; } @@ -418,6 +434,7 @@ class LLParcel BOOL getRecordTransaction() const { return mRecordTransaction; } void setRecordTransaction(BOOL record) { mRecordTransaction = record; } + BOOL isMediaResetTimerExpired(const U64& time); // more accessors U32 getParcelFlags() const { return mParcelFlags; } @@ -595,6 +612,8 @@ class LLParcel LLVector3 mUserLookAt; ELandingType mLandingType; LLTimer mSaleTimerExpires; + LLTimer mMediaResetTimer; + S32 mGraceExtension; BOOL mRecordTransaction; @@ -624,9 +643,15 @@ class LLParcel S32 mMediaHeight; U8 mMediaAutoScale; U8 mMediaLoop; + std::string mMediaCurrentURL; U8 mObscureMedia; U8 mObscureMusic; LLUUID mMediaID; + U8 mMediaURLFilterEnable; + LLSD mMediaURLFilterList; + U8 mMediaAllowNavigate; + U8 mMediaPreventCameraZoom; + F32 mMediaURLTimeout; S32 mPassPrice; F32 mPassHours; LLVector3 mAABBMin; diff --git a/linden/indra/llinventory/lltransactionflags.cpp b/linden/indra/llinventory/lltransactionflags.cpp index aaea16158..fda8cad90 100644 --- a/linden/indra/llinventory/lltransactionflags.cpp +++ b/linden/indra/llinventory/lltransactionflags.cpp @@ -37,7 +37,7 @@ #include "lltransactionflags.h" #include "lltransactiontypes.h" -#include "../newview/hippoGridManager.h" +#include "../newview/hippogridmanager.h" const U8 TRANSACTION_FLAGS_NONE = 0; const U8 TRANSACTION_FLAG_SOURCE_GROUP = 1; diff --git a/linden/indra/llmath/llmath.h b/linden/indra/llmath/llmath.h index 9f8e539dc..0de568cbd 100644 --- a/linden/indra/llmath/llmath.h +++ b/linden/indra/llmath/llmath.h @@ -35,6 +35,7 @@ #include #include +#include #include "lldefs.h" #include "llstl.h" // *TODO: Remove when LLString is gone #include "llstring.h" // *TODO: Remove when LLString is gone @@ -60,7 +61,9 @@ #endif // Single Precision Floating Point Routines -#if _MSC_VER < 1400 +#ifndef fsqrtf +#define fsqrtf(x) ((F32)sqrt((F64)(x))) +#endif #ifndef sqrtf #define sqrtf(x) ((F32)sqrt((F64)(x))) #endif @@ -81,11 +84,6 @@ #ifndef powf #define powf(x,y) ((F32)pow((F64)(x),(F64)(y))) #endif -#endif - -#ifndef fsqrtf -#define fsqrtf(x) sqrtf(x) -#endif const F32 GRAVITY = -9.8f; diff --git a/linden/indra/llmath/lloctree.h b/linden/indra/llmath/lloctree.h index bced84cb1..2029554bf 100644 --- a/linden/indra/llmath/lloctree.h +++ b/linden/indra/llmath/lloctree.h @@ -68,8 +68,7 @@ template class LLOctreeTraveler : public LLTreeTraveler { public: - virtual void traverse(const LLTreeNode* node); - virtual void visit(const LLTreeNode* state) { } + virtual void traverse(const LLOctreeNode* node); virtual void visit(const LLOctreeNode* branch) = 0; }; @@ -705,9 +704,8 @@ class LLOctreeRoot : public LLOctreeNode // LLOctreeTraveler //======================== template -void LLOctreeTraveler::traverse(const LLTreeNode* tree_node) +void LLOctreeTraveler::traverse(const LLOctreeNode* node) { - const LLOctreeNode* node = (const LLOctreeNode*) tree_node; node->accept(this); for (U32 i = 0; i < node->getChildCount(); i++) { diff --git a/linden/indra/llmath/llrect.h b/linden/indra/llmath/llrect.h index 9eb58dbbe..33070c40a 100644 --- a/linden/indra/llmath/llrect.h +++ b/linden/indra/llmath/llrect.h @@ -229,14 +229,14 @@ template class LLRectBase return mLeft <= mRight && mBottom <= mTop; } - bool isNull() const + bool isEmpty() const { return mLeft == mRight || mBottom == mTop; } bool notNull() const { - return !isNull(); + return !isEmpty(); } LLRectBase& unionWith(const LLRectBase &other) diff --git a/linden/indra/llmath/llsdutil_math.h b/linden/indra/llmath/llsdutil_math.h new file mode 100755 index 000000000..5b649425d --- /dev/null +++ b/linden/indra/llmath/llsdutil_math.h @@ -0,0 +1,70 @@ +/** + * @file llsdutil_math.h + * @author Brad + * @date 2009-05-19 + * @brief Utility classes, functions, etc, for using structured data with math classes. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSDUTIL_MATH_H +#define LL_LLSDUTIL_MATH_H + +class LL_COMMON_API LLSD; + +// vector3 +class LLVector3; +LLSD ll_sd_from_vector3(const LLVector3& vec); +LLVector3 ll_vector3_from_sd(const LLSD& sd, S32 start_index = 0); + +// vector4 +class LLVector4; +LLSD ll_sd_from_vector4(const LLVector4& vec); +LLVector4 ll_vector4_from_sd(const LLSD& sd, S32 start_index = 0); + +// vector3d (double) +class LLVector3d; +LLSD ll_sd_from_vector3d(const LLVector3d& vec); +LLVector3d ll_vector3d_from_sd(const LLSD& sd, S32 start_index = 0); + +// vector2 +class LLVector2; +LLSD ll_sd_from_vector2(const LLVector2& vec); +LLVector2 ll_vector2_from_sd(const LLSD& sd); + +// Quaternion +class LLQuaternion; +LLSD ll_sd_from_quaternion(const LLQuaternion& quat); +LLQuaternion ll_quaternion_from_sd(const LLSD& sd); + +// color4 +class LLColor4; +LLSD ll_sd_from_color4(const LLColor4& c); +LLColor4 ll_color4_from_sd(const LLSD& sd); + +#endif // LL_LLSDUTIL_MATH_H diff --git a/linden/indra/llmath/lltreenode.h b/linden/indra/llmath/lltreenode.h index ee9836241..ccbeda57c 100644 --- a/linden/indra/llmath/lltreenode.h +++ b/linden/indra/llmath/lltreenode.h @@ -82,8 +82,6 @@ class LLTreeTraveler { public: virtual ~LLTreeTraveler() { }; - virtual void traverse(const LLTreeNode* node) = 0; - virtual void visit(const LLTreeNode* node) = 0; }; template diff --git a/linden/indra/llmath/llvolume.cpp b/linden/indra/llmath/llvolume.cpp index b9b9e0bb9..c4c3f0795 100644 --- a/linden/indra/llmath/llvolume.cpp +++ b/linden/indra/llmath/llvolume.cpp @@ -3376,7 +3376,8 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, std::vector &segments, const LLVector3& obj_cam_vec, const LLMatrix4& mat, - const LLMatrix3& norm_mat) + const LLMatrix3& norm_mat, + S32 face_mask) { LLMemType m1(LLMemType::MTYPE_VOLUME); @@ -3384,12 +3385,17 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, normals.clear(); segments.clear(); + S32 cur_index = 0; //for each face for (face_list_t::iterator iter = mVolumeFaces.begin(); iter != mVolumeFaces.end(); ++iter) { const LLVolumeFace& face = *iter; + if (!(face_mask & (0x1 << cur_index++))) + { + continue; + } if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { } diff --git a/linden/indra/llmath/llvolume.h b/linden/indra/llmath/llvolume.h index 2b1c60d53..0b9002f66 100644 --- a/linden/indra/llmath/llvolume.h +++ b/linden/indra/llmath/llvolume.h @@ -905,9 +905,13 @@ class LLVolume : public LLRefCount // returns number of triangle indeces required for path/profile mesh S32 getNumTriangleIndices() const; - void generateSilhouetteVertices(std::vector &vertices, std::vector &normals, std::vector &segments, const LLVector3& view_vec, - const LLMatrix4& mat, - const LLMatrix3& norm_mat); + void generateSilhouetteVertices(std::vector &vertices, + std::vector &normals, + std::vector &segments, + const LLVector3& view_vec, + const LLMatrix4& mat, + const LLMatrix3& norm_mat, + S32 face_index); //get the face index of the face that intersects with the given line segment at the point //closest to start. Moves end to the point of intersection. Returns -1 if no intersection. diff --git a/linden/indra/llmath/llvolumemgr.cpp b/linden/indra/llmath/llvolumemgr.cpp index 53641fcea..8bfebcb42 100644 --- a/linden/indra/llmath/llvolumemgr.cpp +++ b/linden/indra/llmath/llvolumemgr.cpp @@ -55,7 +55,7 @@ LLVolumeMgr::LLVolumeMgr() { // the LLMutex magic interferes with easy unit testing, // so you now must manually call useMutex() to use it - //mDataMutex = new LLMutex(gAPRPoolp); + //mDataMutex = new LLMutex; } LLVolumeMgr::~LLVolumeMgr() @@ -222,7 +222,7 @@ void LLVolumeMgr::useMutex() { if (!mDataMutex) { - mDataMutex = new LLMutex(gAPRPoolp); + mDataMutex = new LLMutex; } } diff --git a/linden/indra/llmath/v3math.h b/linden/indra/llmath/v3math.h index 7f96800e2..8c65d9330 100644 --- a/linden/indra/llmath/v3math.h +++ b/linden/indra/llmath/v3math.h @@ -411,8 +411,8 @@ inline bool operator<(const LLVector3 &a, const LLVector3 &b) return (a.mV[0] < b.mV[0] || (a.mV[0] == b.mV[0] && (a.mV[1] < b.mV[1] - || (a.mV[1] == b.mV[1]) - && a.mV[2] < b.mV[2]))); + || ((a.mV[1] == b.mV[1]) + && a.mV[2] < b.mV[2])))); } inline const LLVector3& operator+=(LLVector3 &a, const LLVector3 &b) diff --git a/linden/indra/llmedia/CMakeLists.txt b/linden/indra/llmedia/CMakeLists.txt deleted file mode 100644 index f3c8e30ca..000000000 --- a/linden/indra/llmedia/CMakeLists.txt +++ /dev/null @@ -1,81 +0,0 @@ -# -*- cmake -*- - -project(llmedia) - -include(00-Common) -include(LLAudio) -include(LLCommon) -include(LLImage) -include(LLMath) -include(LLMedia) -include(LLMessage) -include(LLWindow) -include(Mozlib) - -include_directories( - ${GSTREAMER_INCLUDE_DIRS} - ${GSTREAMER_PLUGINS_BASE_INCLUDE_DIRS} - ${GSTREAMER_VIDEO_INCLUDE_DIRS} - ${LLAUDIO_INCLUDE_DIRS} - ${LLCOMMON_INCLUDE_DIRS} - ${LLIMAGE_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLMESSAGE_INCLUDE_DIRS} - ${LLWINDOW_INCLUDE_DIRS} - ) - -set(llmedia_SOURCE_FILES - llmediaimplcommon.cpp - llmediaimplexample1.cpp - llmediaimplexample2.cpp - llmediaimplfactory.cpp - llmediamanager.cpp - llmediaimplgstreamer.cpp - llmediaimplgstreamervidplug.cpp - llgstplaythread.cpp - ) - -set(llmedia_HEADER_FILES - CMakeLists.txt - - llmediabase.h - llmediaemitter.h - llmediaimplcommon.h - llmediaimplexample1.h - llmediaimplexample2.h - llmediaimplfactory.h - llmediaimplregister.h - llmediamanager.h - llmediaobserver.h - llmediaimplgstreamer.h - llmediaimplgstreamervidplug.h - llgstplaythread.h - ) - - # Work around a bad interaction between broken gstreamer headers and - # g++ 4.3's increased strictness. - - if (${CXX_VERSION} MATCHES "4.[23]") - set_source_files_properties(llmediaimplgstreamervidplug.cpp PROPERTIES - COMPILE_FLAGS -Wno-error=write-strings) - endif (${CXX_VERSION} MATCHES "4.[23]") - -if (MOZLIB) - list(APPEND llmedia_SOURCE_FILES llmediaimplllmozlib.cpp) - - list(APPEND llmedia_HEADER_FILES llmediaimplllmozlib.h) -endif (MOZLIB) - -set_source_files_properties(${llmedia_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -list(APPEND llmedia_SOURCE_FILES ${llmedia_HEADER_FILES}) - -add_library (llmedia ${llmedia_SOURCE_FILES}) -target_link_libraries( - llmedia - ${GSTREAMER_LIBRARIES} - ${GSTREAMER_PLUGINS_BASE_LIBRARIES} - ${GSTREAMER_VIDEO_LIBRARIES} - ${QUICKTIME_LIBRARY} - ) diff --git a/linden/indra/llmedia/llgstplaythread.cpp b/linden/indra/llmedia/llgstplaythread.cpp deleted file mode 100644 index 152f9d95c..000000000 --- a/linden/indra/llmedia/llgstplaythread.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file llgstplaythread.cpp - * @author Jacek Antonelli - * @brief GStreamer playback management thread class - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009, Jacek Antonelli - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * $/LicenseInfo$ - */ - -#include "llgstplaythread.h" -#include "llmediaimplgstreamer.h" - -LLGstPlayThread:: -LLGstPlayThread( LLMediaImplCommon *impl, - const std::string& name, apr_pool_t *poolp ): - LLThread( name, poolp ), - mMediaImpl( impl ) -{ -} - - -LLGstPlayThread::~LLGstPlayThread() -{ -} - - -// virtual -void LLGstPlayThread::run() -{ - ((LLMediaImplGStreamer *)mMediaImpl)->startPlay(); -} diff --git a/linden/indra/llmedia/llgstplaythread.h b/linden/indra/llmedia/llgstplaythread.h deleted file mode 100644 index c3c36a746..000000000 --- a/linden/indra/llmedia/llgstplaythread.h +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @file llgstplaythread.h - * @author Jacek Antonelli - * @brief GStreamer playback management thread class - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009, Jacek Antonelli - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * $/LicenseInfo$ - */ - - -#ifndef LL_LLGSTPLAYTHREAD_H -#define LL_LLGSTPLAYTHREAD_H - -#include "linden_common.h" - -#include "llthread.h" -#include "llmediaimplcommon.h" - -class LLGstPlayThread: public LLThread -{ - public: - - LLGstPlayThread( LLMediaImplCommon *impl, - const std::string& name, apr_pool_t *poolp ); - - ~LLGstPlayThread(); - - virtual void run(); - - private: - - // Actually, this will really only be an LLMediaImplGStreamer. - // But we have to jump through some hoops to mutual pointer-holding. - // There may be a better way, but I don't have the motivation to find it. - LLMediaImplCommon *mMediaImpl; -}; - - -#endif // LL_LLGSTPLAYTHREAD_H diff --git a/linden/indra/llmedia/llmediabase.h b/linden/indra/llmedia/llmediabase.h deleted file mode 100644 index 3bcee4ea1..000000000 --- a/linden/indra/llmedia/llmediabase.h +++ /dev/null @@ -1,265 +0,0 @@ -/** - * @file llmediabase.h - * @author Callum Prentice - * @date 2007-10-22 00:00:00 - * @brief Abstract class that defines LLMedia public interface - * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLMEDIABASE_H -#define LLMEDIABASE_H - -#if LL_LLMOZLIB_ENABLED && !defined ( MOZILLA_INTERNAL_API ) - // Without this, nsTAString.h errors out with: - // "Cannot use internal string classes without MOZILLA_INTERNAL_API defined. Use the frozen header nsStringAPI.h instead." - // It might be worth our while to figure out if we can use the frozen apis at some point... - #define MOZILLA_INTERNAL_API 1 -#endif - -#include - -class LLMediaObserver; -class LLMediaImplMakerBase; - -class LLMediaBase -{ - public: - LLMediaBase() {}; - virtual ~LLMediaBase() {}; - - //////////////////////////////////////////////////////////////////////////////// - // housekeeping - - // local initialization, called by the media manager when creating a source - virtual bool init() = 0; - - // undoes everything init() didm called by the media manager when destroying a source - virtual bool reset() = 0; - - - /* Mirrors GStreamer debug levels. */ - enum EDebugLevel { - DEBUG_LEVEL_NONE = 0, - DEBUG_LEVEL_ERROR, - DEBUG_LEVEL_WARNING, - DEBUG_LEVEL_INFO, - DEBUG_LEVEL_DEBUG, - DEBUG_LEVEL_LOG, - DEBUG_LEVEL_COUNT, - }; - - /* Set the debug verbosity level. Only implemented for GStreamer. */ - virtual bool setDebugLevel( EDebugLevel level ) = 0; - - // accessor for MIME type - virtual bool setMimeType( const std::string mime_type ) = 0; - virtual std::string getMimeType() const = 0; - - // accessor for intial URL. Note that this may have changed under the hood - // so pass back the original URL seeded to this impl - virtual std::string getMediaURL() const = 0; - - // ask impl for version string - virtual std::string getVersion() = 0; - - // set/clear URL to visit when a 404 page is reached - virtual bool set404RedirectUrl( std::string redirect_url ) = 0; - virtual bool clr404RedirectUrl() = 0; - - // sets the background color of the browser window - virtual bool setBackgroundColor( unsigned int red, unsigned int green, unsigned int blue ) const = 0; - - // sets the color of the caret in media impls that have one - virtual bool setCaretColor( unsigned int red, unsigned int green, unsigned int blue ) const = 0; - - //////////////////////////////////////////////////////////////////////////////// - // media management - - // needs to be called regularly to make media stream update itself - virtual bool updateMedia() = 0; - - // allows you to request a change in media width, height - may fail if media doesn't support size change - virtual bool setRequestedMediaSize( int media_width, int media_height ) = 0; - - // gets media width (may change throughout lifetime of media stream) - event emitted when media size changed too - virtual int getMediaWidth() const = 0; - - // gets media height (may change throughout lifetime of media stream) - event emitted when media size changed too - virtual int getMediaHeight() const = 0; - - // allows you to try to explicitly change media depth - may fail if media doesn't support depth change - virtual bool setMediaDepth( int media_depth ) = 0; - - // gets media depth (may change throughout lifetime of media stream) - event emitted when media depth changed too - virtual int getMediaDepth() const = 0; - - // gets size of media buffer for current frame (might NOT be the same as media width * height * depth) - virtual int getMediaBufferSize() const = 0; - - // returns pointer to raw media pixels - virtual unsigned char* getMediaData() = 0; - - // returns the size of the data, which may be different that the size of the media - virtual int getMediaDataWidth() const = 0; - virtual int getMediaDataHeight() const = 0; - - //////////////////////////////////////////////////////////////////////////////// - // texture management - - // gets internal format to use for OpenGL texture - virtual int getTextureFormatInternal() const = 0; - - // gets primary format to use for OpenGL texture - virtual int getTextureFormatPrimary() const = 0; - - // gets format type to use for OpenGL texture - virtual int getTextureFormatType() const = 0; - - - - - //////////////////////////////////////////////////////////////////////////////// - // audio - - // set/get control volume from media stream if present - virtual bool setVolume( float volume ) = 0; - virtual float getVolume() const = 0; - - - //////////////////////////////////////////////////////////////////////////////// - // transport control etc. - enum ECommand { - COMMAND_NONE = 0, - COMMAND_STOP = 1, - COMMAND_START = 2, - COMMAND_PAUSE = 4, - COMMAND_BACK = 5, - COMMAND_FORWARD = 6 - }; - enum EStatus { - STATUS_UNKNOWN = 0, - STATUS_INITIALIZING = 1, - STATUS_NAVIGATING = 2, - STATUS_STARTED = 3, - STATUS_STOPPED = 4, - STATUS_PAUSED = 6, - STATUS_RESETTING = 7, - STATUS_DEAD = 8 - }; - virtual bool addCommand( ECommand cmd ) = 0; - virtual bool clearCommand() = 0; - virtual bool updateCommand() = 0; - virtual EStatus getStatus() = 0; - virtual bool seek( double time ) = 0; - virtual bool setLooping( bool enable) = 0; - virtual bool isLooping() = 0; - - //////////////////////////////////////////////////////////////////////////////// - // scaling - - // autoscale means try to scale media to size of texture - may fail if media doesn't support size change - virtual bool setAutoScaled( bool auto_scaled ) = 0; - virtual bool isAutoScaled() const = 0; - - - //////////////////////////////////////////////////////////////////////////////// - // mouse and keyboard interaction - virtual bool mouseDown( int x_pos, int y_pos ) = 0; - virtual bool mouseUp( int x_pos, int y_pos ) = 0; - virtual bool mouseMove( int x_pos, int y_pos ) = 0; - virtual bool keyPress( int key_code ) = 0; - virtual bool scrollByLines( int lines ) = 0; - virtual bool focus( bool focus ) = 0; - virtual bool unicodeInput( unsigned long uni_char ) = 0; - virtual bool mouseLeftDoubleClick( int x_pos, int y_pos ) = 0; - - - //////////////////////////////////////////////////////////////////////////////// - // navigation - virtual bool navigateTo( const std::string url ) = 0; - virtual bool navigateForward() = 0; - virtual bool navigateBack() = 0; - virtual bool canNavigateForward() = 0; - virtual bool canNavigateBack() = 0; - - //////////////////////////////////////////////////////////////////////////////// - // caching/cookies - virtual bool enableCookies( bool enable ) = 0; - virtual bool clearCache() = 0; - virtual bool clearCookies() = 0; - - //////////////////////////////////////////////////////////////////////////////// - // proxy - virtual bool enableProxy(bool enable, std::string proxy_host_name, int proxy_port) = 0; - - //////////////////////////////////////////////////////////////////////////////// - // observer interface - virtual bool addObserver( LLMediaObserver* subject ) = 0; - virtual bool remObserver( LLMediaObserver* subject ) = 0; - - //////////////////////////////////////////////////////////////////////////////// - // factory interface - virtual void setImplMaker(LLMediaImplMakerBase* impl_maker) = 0; - - //////////////////////////////////////////////////////////////////////////////// - // type registry interface - virtual bool supportsMediaType(std::string scheme, std::string type) = 0; -}; - -////////////////////////////////////////////////////////////// -// media key codes - (mirroring mozilla's values) -const unsigned long LL_MEDIA_KEY_BACKSPACE = 0x08; -const unsigned long LL_MEDIA_KEY_TAB = 0x09; -const unsigned long LL_MEDIA_KEY_RETURN = 0x0D; -const unsigned long LL_MEDIA_KEY_PAD_RETURN = 0x0E; -const unsigned long LL_MEDIA_KEY_ESCAPE = 0x1B; -const unsigned long LL_MEDIA_KEY_PAGE_UP = 0x21; -const unsigned long LL_MEDIA_KEY_PAGE_DOWN = 0x22; -const unsigned long LL_MEDIA_KEY_END = 0x23; -const unsigned long LL_MEDIA_KEY_HOME = 0x24; -const unsigned long LL_MEDIA_KEY_LEFT = 0x25; -const unsigned long LL_MEDIA_KEY_UP = 0x26; -const unsigned long LL_MEDIA_KEY_RIGHT = 0x27; -const unsigned long LL_MEDIA_KEY_DOWN = 0x28; -const unsigned long LL_MEDIA_KEY_INSERT = 0x2D; -const unsigned long LL_MEDIA_KEY_DELETE = 0x2E; - -////////////////////////////////////////////////////////////// -// media frame buffer types - (mirroring GL values) -const int LL_MEDIA_UNSIGNED_BYTE = 0x1401; -const int LL_MEDIA_RGB = 0x1907; -const int LL_MEDIA_RGBA = 0x1908; -const int LL_MEDIA_RGB8 = 0x8051; -const int LL_MEDIA_UNSIGNED_INT_8_8_8_8 = 0x8035; -const int LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV = 0x8367; -const int LL_MEDIA_BGR = 0x80E0; -const int LL_MEDIA_BGRA = 0x80E1; - - -#endif // LLMEDIABASE_H diff --git a/linden/indra/llmedia/llmediaemitter.h b/linden/indra/llmedia/llmediaemitter.h deleted file mode 100644 index ef3caeb5c..000000000 --- a/linden/indra/llmedia/llmediaemitter.h +++ /dev/null @@ -1,104 +0,0 @@ -/** - * @file llmediaemitter.h - * @author Callum Prentice - * @date 2007-10-22 00:00:00 - * @brief Manages and emits events to observers - * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLMEDIAEMITTER_H -#define LLMEDIAEMITTER_H - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// -// -template< class T > -class LLMediaEmitter -{ - public: - LLMediaEmitter() { }; - ~LLMediaEmitter() { }; - - typedef typename T::EventType EventType; - typedef std::list< T* > ObserverContainer; - typedef void( T::*observerMethod )( const EventType& ); - - /////////////////////////////////////////////////////////////////////////////// - // - bool addObserver( T* observer_in ) - { - if ( ! observer_in ) - return false; - - if ( std::find( observers.begin(), observers.end(), observer_in) != observers.end() ) - return false; - - observers.push_back( observer_in ); - - return true; - }; - - /////////////////////////////////////////////////////////////////////////////// - // - bool remObserver( T* observer_in ) - { - if ( ! observer_in ) - return false; - - observers.remove( observer_in ); - observers.remove( observer_in ); - observers.remove( observer_in ); - - - - return true; - }; - - /////////////////////////////////////////////////////////////////////////////// - // - void update( observerMethod method, const EventType& msgIn ) - { - typename std::list< T* >::iterator iter = observers.begin(); - - while( iter != observers.end() ) - { - ( ( *iter )->*method )( msgIn ); - - ++iter; - }; - }; - - protected: - ObserverContainer observers; -}; - -#endif // LLMEDIAEMITTER_H diff --git a/linden/indra/llmedia/llmediaimplcommon.cpp b/linden/indra/llmedia/llmediaimplcommon.cpp deleted file mode 100644 index 166e86d2a..000000000 --- a/linden/indra/llmedia/llmediaimplcommon.cpp +++ /dev/null @@ -1,552 +0,0 @@ -/** - * @file llmediaimplcommon.cpp - * @brief Common impl functionality - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llmediaimplcommon.h" -#include "llmediaemitter.h" -#include "llmediaimplfactory.h" -#include "llmediaobserver.h" - -#ifdef WIN32 - // platform specific includes needed before OpenGL header - #include - #include -#elif defined(__APPLE__) - // framework-style include path when building on the Mac. - #include -#else // Assume this is linux - // Linux, MESA headers, but not necessarily assuming MESA runtime. - // quotes so we get libraries/.../GL/ version - #include "GL/gl.h" -#endif - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -LLMediaImplCommon::LLMediaImplCommon() : - mMimeType( std::string() ), - mInitialURL( std::string() ), - mImplMaker( NULL ), - mAutoScaled( false ), - mMediaWidth( 0 ), - mMediaPrevWidth( 0 ), - mMediaHeight( 0 ), - mMediaPrevHeight( 0 ), - mMediaDepth( 0 ), - mMediaPrevDepth( 0 ), - mMediaRowSpan( 0 ), - mMediaRequestedWidth( 0 ), - mMediaRequestedHeight( 0 ), - mCommand( LLMediaBase::COMMAND_NONE ), - mStatus( LLMediaBase::STATUS_UNKNOWN ), - mVolume( 0 ), - mLooping( false ), - mDebugLevel( LLMediaBase::DEBUG_LEVEL_NONE ) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -LLMediaImplCommon::~LLMediaImplCommon() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::init() -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::reset() -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::setDebugLevel( LLMediaBase::EDebugLevel level ) -{ - mDebugLevel = level; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::setMimeType( const std::string mime_type ) -{ - mMimeType = mime_type; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -std::string LLMediaImplCommon::getMimeType() const -{ - return mMimeType; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -std::string LLMediaImplCommon::getMediaURL() const -{ - return mInitialURL; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -std::string LLMediaImplCommon::getVersion() -{ - return std::string( "" ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::set404RedirectUrl( std::string redirect_url ) -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::clr404RedirectUrl() -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::setBackgroundColor( unsigned int red, unsigned int green, unsigned int blue ) const -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::setCaretColor( unsigned int red, unsigned int green, unsigned int blue ) const -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::updateMedia() -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -unsigned char* LLMediaImplCommon::getMediaData() -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -int LLMediaImplCommon::getMediaDataWidth() const -{ - return getMediaWidth(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -int LLMediaImplCommon::getMediaDataHeight() const -{ - return getMediaHeight(); -} - - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::setMediaSize( int media_width, int media_height ) -{ - // if nothing changed, don't do anything - if ( ( mMediaWidth == media_width ) && - ( mMediaHeight == media_height ) ) - return false; - - // save old values so we can tell elsewhere if media size has changed - mMediaPrevWidth = mMediaWidth; - mMediaPrevHeight = mMediaHeight; - - mMediaWidth = media_width; - mMediaHeight = media_height; - - // only fire an event if the width changed - LLMediaEvent event( this ); - mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -int LLMediaImplCommon::getMediaWidth() const -{ - return mMediaWidth; -} - - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -int LLMediaImplCommon::getMediaHeight() const -{ - return mMediaHeight; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::setRequestedMediaSize(int width, int height) -{ - mMediaRequestedWidth = width; - mMediaRequestedHeight = height; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::setMediaDepth( int media_depth ) -{ - // if nothing changed, don't do anything - if ( mMediaDepth == media_depth ) - return false; - - // save old values so we can tell elsewhere if media size has changed - mMediaPrevDepth = mMediaDepth; - mMediaDepth = media_depth; - - // update value of rowspan too since it's based on media width & depth - mMediaRowSpan = mMediaWidth * mMediaDepth; - - // only fire an event if the depth changed - //LLMediaEvent event( this ); - //mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -int LLMediaImplCommon::getMediaDepth() const -{ - return mMediaDepth; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -int LLMediaImplCommon::getMediaBufferSize() const -{ - return mMediaRowSpan * mMediaHeight; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -int LLMediaImplCommon::getTextureFormatInternal() const -{ - return LL_MEDIA_RGB; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -int LLMediaImplCommon::getTextureFormatPrimary() const -{ - return LL_MEDIA_RGB; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -int LLMediaImplCommon::getTextureFormatType() const -{ - return LL_MEDIA_UNSIGNED_BYTE; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::setVolume( float volume ) -{ - mVolume = volume; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -float LLMediaImplCommon::getVolume() const -{ - return mVolume; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::addCommand( LLMediaBase::ECommand cmd ) -{ - // eventually will be a std::queue so you can add multiple commands - mCommand = cmd; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::clearCommand() -{ - // eventually will be a std::queue so you can add multiple commands - mCommand = LLMediaBase::COMMAND_NONE; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::updateCommand() -{ - if ( nextCommand() == LLMediaBase::COMMAND_START ) - { - setStatus( LLMediaBase::STATUS_STARTED ); - clearCommand(); - }; - - if ( nextCommand() == LLMediaBase::COMMAND_STOP ) - { - setStatus( LLMediaBase::STATUS_STOPPED ); - clearCommand(); - }; - - if ( nextCommand() == LLMediaBase::COMMAND_PAUSE ) - { - setStatus( LLMediaBase::STATUS_PAUSED ); - clearCommand(); - }; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// non-virtual (only impls use this) -LLMediaBase::ECommand LLMediaImplCommon::nextCommand() -{ - return mCommand; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -LLMediaBase::EStatus LLMediaImplCommon::getStatus() -{ - return mStatus; -} - -//////////////////////////////////////////////////////////////////////////////// -// non-virtual (only impls set this) -bool LLMediaImplCommon::setStatus( LLMediaBase::EStatus status ) -{ - mStatus = status; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::seek( double time ) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::navigateTo( const std::string url ) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::setAutoScaled( bool auto_scaled ) -{ - mAutoScaled = auto_scaled; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::isAutoScaled() const -{ - return mAutoScaled; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::mouseDown( int x_pos, int y_pos ) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::mouseUp( int x_pos, int y_pos ) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::mouseMove( int x_pos, int y_pos ) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::keyPress( int key_code ) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::scrollByLines( int lines ) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::focus( bool focus ) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::unicodeInput( unsigned long uni_char ) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::mouseLeftDoubleClick( int x_pos, int y_pos ) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::navigateForward() -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::navigateBack() -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::canNavigateForward() -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::canNavigateBack() -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::enableCookies( bool enable ) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::clearCache() -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::clearCookies() -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual (derives from LLMediaBase) -bool LLMediaImplCommon::enableProxy(bool enable, std::string proxy_host_name, int proxy_port) -{ - return false; -} -//////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaImplCommon::addObserver( LLMediaObserver* subject ) -{ - return mEventEmitter.addObserver( subject ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaImplCommon::remObserver( LLMediaObserver* subject ) -{ - return mEventEmitter.remObserver( subject ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLMediaImplCommon::setImplMaker(LLMediaImplMakerBase* impl_maker) -{ - mImplMaker = impl_maker; -} -//////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaImplCommon::supportsMediaType(std::string scheme, std::string type) -{ - int idx1 = type.find("/"); - int len = (idx1 == std::string::npos) ? 0 : idx1; - std::string category = type.substr(0,len); - - return mImplMaker->supportsScheme(scheme) || - mImplMaker->supportsMimeType(type) || - mImplMaker->supportsMimeTypeCategory(category); -} diff --git a/linden/indra/llmedia/llmediaimplcommon.h b/linden/indra/llmedia/llmediaimplcommon.h deleted file mode 100644 index 845429cf8..000000000 --- a/linden/indra/llmedia/llmediaimplcommon.h +++ /dev/null @@ -1,164 +0,0 @@ -/** - * @file llmediaimplcommon.h - * @brief Common impl functionality - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLMEDIAIMPLCOMMON_H -#define LLMEDIAIMPLCOMMON_H - -#include "llmediabase.h" -#include "llmediaemitter.h" -#include "llmediaobserver.h" - -#include - -class LLMediaImplMakerBase; - -class LLMediaImplCommon : - public LLMediaBase -{ - public: - LLMediaImplCommon(); - virtual ~LLMediaImplCommon(); - - //////////////////////////////////////////////////////////////////////////////// - // begin: default implementation of the abstract interface - // see llmediabase.h for documentation - - // housekeeping - virtual bool init(); - virtual bool reset(); - virtual bool setDebugLevel( LLMediaBase::EDebugLevel level ); - virtual bool setMimeType( const std::string url ); - virtual std::string getMimeType() const; - virtual std::string getMediaURL() const; - virtual std::string getVersion(); - virtual bool set404RedirectUrl( std::string redirect_url ); - virtual bool clr404RedirectUrl(); - virtual bool setBackgroundColor( unsigned int red, unsigned int green, unsigned int blue ) const; - virtual bool setCaretColor( unsigned int red, unsigned int green, unsigned int blue ) const; - - // media management - virtual bool updateMedia(); - virtual bool setRequestedMediaSize( int width, int height ); - virtual int getMediaWidth() const; - virtual int getMediaHeight() const; - virtual int getMediaDepth() const; - virtual int getMediaBufferSize() const; - virtual unsigned char* getMediaData(); - virtual int getMediaDataWidth() const; - virtual int getMediaDataHeight() const; - - // texture management - virtual int getTextureFormatInternal() const; - virtual int getTextureFormatPrimary() const; - virtual int getTextureFormatType() const; - - // audio - virtual bool setVolume( float volume ); - virtual float getVolume() const; - - // transport control - virtual bool addCommand( ECommand cmd ); - virtual bool clearCommand(); - virtual bool updateCommand(); - LLMediaBase::ECommand nextCommand(); - virtual LLMediaBase::EStatus getStatus(); - bool setStatus( LLMediaBase::EStatus status ); - - virtual bool seek( double time ); - virtual bool setLooping(bool enable) { mLooping = enable; return true; } - virtual bool isLooping() { return mLooping; } - virtual bool navigateTo( const std::string url ); - - // scaling - virtual bool setAutoScaled( bool auto_scaled ); - virtual bool isAutoScaled() const; - - // mouse and keyboard interaction - virtual bool mouseDown( int x_pos, int y_pos ); - virtual bool mouseUp( int x_pos, int y_pos ); - virtual bool mouseMove( int x_pos, int y_pos ); - virtual bool keyPress( int key_code ); - virtual bool scrollByLines( int lines ); - virtual bool focus( bool focus ); - virtual bool unicodeInput( unsigned long uni_char ); - virtual bool mouseLeftDoubleClick( int x_pos, int y_pos ); - - // navigation - virtual bool navigateForward(); - virtual bool navigateBack(); - virtual bool canNavigateForward(); - virtual bool canNavigateBack(); - - // caching/cookies - virtual bool enableCookies( bool enable ); - virtual bool clearCache(); - virtual bool clearCookies(); - - virtual bool enableProxy(bool enable, std::string proxy_host_name, int proxy_port); - - // observer interface - bool addObserver( LLMediaObserver* subject ); - bool remObserver( LLMediaObserver* subject ); - - // type registry interface - void setImplMaker(LLMediaImplMakerBase* impl_maker); - bool supportsMediaType(std::string scheme, std::string type); - - protected: - virtual bool setMediaSize( int width, int height ); - virtual bool setMediaDepth( int media_depth ); - - LLMediaEmitter< LLMediaObserver > mEventEmitter; - - // Back pointer to the construction object, which is used to discover types handled - // by the Impl, and meta data associated with the Impl. - LLMediaImplMakerBase* mImplMaker; - std::string mMimeType; - std::string mInitialURL; - bool mAutoScaled; - int mMediaWidth; - int mMediaPrevWidth; - int mMediaHeight; - int mMediaPrevHeight; - int mMediaDepth; - int mMediaPrevDepth; - int mMediaRowSpan; - int mMediaRequestedWidth; - int mMediaRequestedHeight; - float mVolume; - LLMediaBase::ECommand mCommand; - LLMediaBase::EStatus mStatus; - bool mLooping; - LLMediaBase::EDebugLevel mDebugLevel; -}; - -#endif // LLMEDIAIMPLCOMMON_H diff --git a/linden/indra/llmedia/llmediaimplexample1.cpp b/linden/indra/llmedia/llmediaimplexample1.cpp deleted file mode 100644 index fe7b7e286..000000000 --- a/linden/indra/llmedia/llmediaimplexample1.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/** - * @file llmediaimplexample1.cpp - * @brief Example 1 of a media impl concrete class - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llmediaimplexample1.h" -#include "llmediaimplregister.h" - -#include - -// register this impl with media manager factory -static LLMediaImplRegister sLLMediaImplExample1Reg( "LLMediaImplExample1", new LLMediaImplExample1Maker() ); - -#include - -#include - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplExample1Maker::LLMediaImplExample1Maker() -{ - // Register to handle the scheme - mSchema.push_back( "example1" ); -} - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplExample1::LLMediaImplExample1() : - mMediaPixels( 0 ) -{ - setRequestedMediaSize( 400, 200 ); - setMediaDepth( 3 ); - - srand( (unsigned int)(time( NULL )) ); -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) super-initialization - called once at application startup -bool LLMediaImplExample1::startup( LLMediaManagerData* init_data ) -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) super-uninitialization - called once at application closedown -bool LLMediaImplExample1::closedown() -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplExample1::init() -{ - int buffer_size = getMediaBufferSize(); - - mMediaPixels = new unsigned char[ buffer_size ]; - - memset( mMediaPixels, 0xAA, buffer_size ); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplExample1::navigateTo( const std::string url ) -{ - std::cout << "LLMediaImplExample1::navigateTo" << std::endl; - - setStatus( LLMediaBase::STATUS_NAVIGATING ); - - // force a size change event for new URL - LLMediaEvent event( this ); - mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -std::string LLMediaImplExample1::getVersion() -{ - std::string version_string = "[" + sLLMediaImplExample1Reg.getImplName() + "] - " + "1.0.0.0"; - - return version_string; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplExample1::updateMedia() -{ - if ( mMediaPixels && getStatus() == LLMediaBase::STATUS_STARTED ) - { - // first time - make sure it's a few seconds back so first update happens immediately - static time_t t = time( 0 ) - 4; - - // selected time period elapsed (1 second) - if ( time( 0 ) - t > 1 ) - { - // display checkerboard - const int num_squares = rand() % 20 + 4; - int sqr1_r = rand() % 0x80; - int sqr1_g = rand() % 0x80; - int sqr1_b = rand() % 0x80; - int sqr2_r = rand() % 0x80; - int sqr2_g = rand() % 0x80; - int sqr2_b = rand() % 0x80; - - for ( int y1 = 0; y1 < num_squares; ++y1 ) - { - for ( int x1 = 0; x1 < num_squares; ++x1 ) - { - int px_start = getMediaWidth() * x1 / num_squares; - int px_end = ( getMediaWidth() * ( x1 + 1 ) ) / num_squares; - int py_start = getMediaHeight() * y1 / num_squares; - int py_end = ( getMediaHeight() * ( y1 + 1 ) ) / num_squares; - - for( int y2 = py_start; y2 < py_end; ++y2 ) - { - for( int x2 = px_start; x2 < px_end; ++x2 ) - { - int rowspan = getMediaWidth() * getMediaDepth(); - - if ( ( y1 % 2 ) ^ ( x1 % 2 ) ) - { - mMediaPixels[ y2 * rowspan + x2 * getMediaDepth() + 0 ] = sqr1_r; - mMediaPixels[ y2 * rowspan + x2 * getMediaDepth() + 1 ] = sqr1_g; - mMediaPixels[ y2 * rowspan + x2 * getMediaDepth() + 2 ] = sqr1_b; - } - else - { - mMediaPixels[ y2 * rowspan + x2 * getMediaDepth() + 0 ] = sqr2_r; - mMediaPixels[ y2 * rowspan + x2 * getMediaDepth() + 1 ] = sqr2_g; - mMediaPixels[ y2 * rowspan + x2 * getMediaDepth() + 2 ] = sqr2_b; - }; - }; - }; - }; - }; - - // emit an event to say that something in the media stream changed - LLMediaEvent event( this ); - mEventEmitter.update( &LLMediaObserver::onMediaContentsChange, event ); - - // reset time - t = time( 0 ); - - return true; - }; - }; - - // update the command (e.g. transport controls) state - updateCommand(); - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -unsigned char* LLMediaImplExample1::getMediaData() -{ - return mMediaPixels; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplExample1::reset() -{ - if ( mMediaPixels ) - { - delete [] mMediaPixels; - }; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplExample1::mouseMove( int x_pos, int y_pos ) -{ - if ( mMediaPixels && getStatus() == LLMediaBase::STATUS_STARTED ) - { - int base_pos = x_pos * getMediaDepth() + y_pos * getMediaDepth() * getMediaWidth(); - // example: write a bright pixel to the display when we move the mouse - mMediaPixels[ base_pos + 0 ] = rand() % 0x80 + 0x80; - mMediaPixels[ base_pos + 1 ] = rand() % 0x80 + 0x80; - mMediaPixels[ base_pos + 2 ] = rand() % 0x80 + 0x80; - - // emit an event to say that something in the media stream changed - LLMediaEvent event( this ); - mEventEmitter.update( &LLMediaObserver::onMediaContentsChange, event ); - }; - - return true; -} - - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplExample1::setRequestedMediaSize( int width, int height ) -{ - // we accept any size: - return setMediaSize(width, height); -} diff --git a/linden/indra/llmedia/llmediaimplexample2.cpp b/linden/indra/llmedia/llmediaimplexample2.cpp deleted file mode 100644 index 7590e19b0..000000000 --- a/linden/indra/llmedia/llmediaimplexample2.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/** - * @file llmediaimplexample2.cpp - * @brief Example 2 of a media impl concrete class - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llmediaimplexample2.h" -#include "llmediaimplregister.h" - -#include - -// register this impl with media manager factory -static LLMediaImplRegister sLLMediaImplExample2Reg( "LLMediaImplExample2", new LLMediaImplExample2Maker() ); - -#include -#include - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplExample2Maker::LLMediaImplExample2Maker() -{ - // Register to handle the scheme - mSchema.push_back( "example2." ); -} - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplExample2::LLMediaImplExample2() : - mMediaPixels( 0 ) -{ - setRequestedMediaSize( 500, 500 ); - setMediaDepth( 3 ); - - mXpos = ( getMediaWidth() / 2 ) + rand() % ( getMediaWidth() / 16 ) - ( getMediaWidth() / 32 ); - mYpos = ( getMediaHeight() / 2 ) + rand() % ( getMediaHeight() / 16 ) - ( getMediaHeight() / 32 ); - - srand( (unsigned int)(time( NULL )) ); -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) super-initialization - called once at application startup -bool LLMediaImplExample2::startup( LLMediaManagerData* init_data ) -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) super-uninitialization - called once at application closedown -bool LLMediaImplExample2::closedown() -{ - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplExample2::init() -{ - int buffer_size = getMediaBufferSize(); - - mMediaPixels = new unsigned char[ buffer_size ]; - - memset( mMediaPixels, 0x00, buffer_size ); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplExample2::navigateTo( const std::string url ) -{ - std::cout << "LLMediaImplExample2::navigateTo" << std::endl; - - setStatus( LLMediaBase::STATUS_NAVIGATING ); - - // force a size change event for new URL - LLMediaEvent event( this ); - mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -std::string LLMediaImplExample2::getVersion() -{ - std::string version_string = "[" + sLLMediaImplExample2Reg.getImplName() + "] - " + "1.0.0.0"; - - return version_string; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplExample2::updateMedia() -{ - if ( mMediaPixels && getStatus() == LLMediaBase::STATUS_STARTED ) - { - static int x_inc = rand() % 5 + 2; - static int y_inc = rand() % 5 + 2; - int block_size = 32; - - for( int y = 0; y < block_size; ++y ) - { - for( int x = 0; x < block_size; ++x ) - { - int rowspan = getMediaWidth() * getMediaDepth(); - mMediaPixels[ ( mXpos + x ) * getMediaDepth() + ( mYpos + y ) * rowspan + 0 ] = 0; - mMediaPixels[ ( mXpos + x ) * getMediaDepth() + ( mYpos + y ) * rowspan + 1 ] = 0; - mMediaPixels[ ( mXpos + x ) * getMediaDepth() + ( mYpos + y ) * rowspan + 2 ] = 0; - }; - }; - - if ( mXpos + x_inc < 0 || mXpos + x_inc >= getMediaWidth() - block_size ) - x_inc =- x_inc; - - if ( mYpos + y_inc < 0 || mYpos + y_inc >= getMediaHeight() - block_size ) - y_inc =- y_inc; - - mXpos += x_inc; - mYpos += y_inc; - - unsigned char col_r = rand() % 0xff; - unsigned char col_g = rand() % 0xff; - unsigned char col_b = rand() % 0xff; - - for( int y = 0; y < block_size; ++y ) - { - for( int x = 0; x < block_size; ++x ) - { - int rowspan = getMediaWidth() * getMediaDepth(); - mMediaPixels[ ( mXpos + x ) * getMediaDepth() + ( mYpos + y ) * rowspan + 0 ] = col_r; - mMediaPixels[ ( mXpos + x ) * getMediaDepth() + ( mYpos + y ) * rowspan + 1 ] = col_g; - mMediaPixels[ ( mXpos + x ) * getMediaDepth() + ( mYpos + y ) * rowspan + 2 ] = col_b; - }; - }; - - // emit an event to say that something in the media stream changed - LLMediaEvent event( this ); - mEventEmitter.update( &LLMediaObserver::onMediaContentsChange, event ); - }; - - // update the command (e.g. transport controls) state - updateCommand(); - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -unsigned char* LLMediaImplExample2::getMediaData() -{ - return mMediaPixels; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplExample2::reset() -{ - if ( mMediaPixels ) - { - delete [] mMediaPixels; - }; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplExample2::setRequestedMediaSize( int width, int height ) -{ - // we accept any size: - return setMediaSize(width, height); -} diff --git a/linden/indra/llmedia/llmediaimplfactory.cpp b/linden/indra/llmedia/llmediaimplfactory.cpp deleted file mode 100644 index c5d098f74..000000000 --- a/linden/indra/llmedia/llmediaimplfactory.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @file llmediaimplfactory.cpp - * @brief Creates media impls that have registered themselves with LLMediaRegster - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llmediaimplfactory.h" - -#include - -LLMediaImplFactory* LLMediaImplFactory::sInstance = NULL; - -/////////////////////////////////////////////////////////////////////////////// -// static -LLMediaImplFactory* LLMediaImplFactory::getInstance() -{ - if ( ! sInstance ) - sInstance = new LLMediaImplFactory(); - - return sInstance; -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLMediaImplFactory::registerImpl( const std::string& impl_name, LLMediaImplMakerBase* impl_maker ) -{ - mNameImplMakerContainer.insert( name_impl_maker_container_t::value_type( impl_name, impl_maker ) ); -} - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplMakerBase* LLMediaImplFactory::getImplMaker( const std::string& scheme, const std::string& type ) -{ - name_impl_maker_container_t::const_iterator iter; - name_impl_maker_container_t::const_iterator begin = mNameImplMakerContainer.begin(); - name_impl_maker_container_t::const_iterator end = mNameImplMakerContainer.end(); - - for(iter = begin; iter != end; ++iter) - { - if(( *iter->second ).supportsScheme(scheme)) - { - return ( iter->second ); - } - } - - for(iter = begin; iter != end; ++iter) - { - if(( *iter->second ).supportsMimeType(type)) - { - return ( iter->second ); - } - } - int idx1 = type.find("/"); - int len = (idx1 == std::string::npos) ? 0 : idx1; - std::string category = type.substr(0,len); - for(iter = begin; iter != end; ++iter) - { - if(( *iter->second ).supportsMimeTypeCategory(category)) - { - return ( iter->second ); - } - } - - return NULL; -}; - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplMakerBase* LLMediaImplFactory::getImplMaker( const std::string& impl_name ) -{ - name_impl_maker_container_t::const_iterator found = mNameImplMakerContainer.find( impl_name ); - - if ( found == mNameImplMakerContainer.end() ) - { - return NULL; - }; - - return found->second; -} diff --git a/linden/indra/llmedia/llmediaimplfactory.h b/linden/indra/llmedia/llmediaimplfactory.h deleted file mode 100644 index 93a7cc10e..000000000 --- a/linden/indra/llmedia/llmediaimplfactory.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file llmediaimplfactory.h - * @brief Creates media impls that have registered themselves with LLMediaRegster - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLMEDIAIMPLFACTORY_H -#define LLMEDIAIMPLFACTORY_H - -#include -#include -#include -#include - -#include "llmediabase.h" - -/////////////////////////////////////////////////////////////////////////////// -// -class LLMediaImplMakerBase -{ - public: - virtual bool supportsScheme(std::string scheme) = 0; - virtual bool supportsMimeType(std::string type) = 0; - virtual bool supportsMimeTypeCategory(std::string category) = 0; - virtual LLMediaBase* create() = 0; - virtual ~LLMediaImplMakerBase() {}; - - protected: - typedef std::vector vector_impl_registry_t; - vector_impl_registry_t mSchema; - vector_impl_registry_t mMimeTypes; - vector_impl_registry_t mMimeTypeCategories; -}; - -/////////////////////////////////////////////////////////////////////////////// -// -class LLMediaImplMaker : public LLMediaImplMakerBase -{ - public: - bool supportsScheme(std::string scheme) - { - vector_impl_registry_t::iterator found = std::find(mSchema.begin(), mSchema.end(), scheme); - return found != mSchema.end(); - } - bool supportsMimeType(std::string type) - { - vector_impl_registry_t::iterator found = std::find(mMimeTypes.begin(), mMimeTypes.end(), type); - return found != mMimeTypes.end(); - } - bool supportsMimeTypeCategory(std::string category) - { - vector_impl_registry_t::iterator found = std::find(mMimeTypeCategories.begin(), mMimeTypeCategories.end(), category); - return found != mMimeTypeCategories.end(); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// -class LLMediaImplFactory -{ - public: - static LLMediaImplFactory* getInstance(); - void registerImpl( const std::string& impl_name, LLMediaImplMakerBase* impl_maker ); - LLMediaImplMakerBase* getImplMaker( const std::string& scheme, const std::string& type ); - LLMediaImplMakerBase* getImplMaker( const std::string& impl_name); - - private: - typedef std::map< std::string, LLMediaImplMakerBase* > name_impl_maker_container_t; - name_impl_maker_container_t mNameImplMakerContainer; - - static LLMediaImplFactory* sInstance; -}; - -#endif // LLMEDIAIMPLFACTORY_H diff --git a/linden/indra/llmedia/llmediaimplgstreamer.cpp b/linden/indra/llmedia/llmediaimplgstreamer.cpp deleted file mode 100644 index 7af9c9ae4..000000000 --- a/linden/indra/llmedia/llmediaimplgstreamer.cpp +++ /dev/null @@ -1,928 +0,0 @@ -/** - * @file llmediaimplgstreamer.cpp - * @author Tofu Linden - * @brief implementation that supports various media through GStreamer. - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -///#if LL_GSTREAMER_ENABLED - -#if LL_WINDOWS - // GStreamer 0.10.22 - gstutils.h - conversion from 'guint64' to 'guint8'. - // This was an intentional change to make GStreamer more threadsafe, and - // is okay. Delete this bit if GStreamer ever gets more VS-friendly -- McCabe - #pragma warning(disable : 4244) -#endif - -#include "linden_common.h" -#include "llmediaimplgstreamer.h" - -extern "C" { -#include -#include -} - -#if LL_WINDOWS - #pragma warning(default : 4244) -#include -#include -#endif - -#include "llmediamanager.h" -#include "llmediaimplregister.h" - -#include "llmediaimplgstreamervidplug.h" -#include "llgstplaythread.h" - - -#if LL_DARWIN -#include // For CF functions used in set_gst_plugin_path -#endif - -// register this impl with media manager factory -static LLMediaImplRegister sLLMediaImplGStreamerReg( "LLMediaImplGStreamer", new LLMediaImplGStreamerMaker() ); - -LLMediaImplGStreamerMaker::LLMediaImplGStreamerMaker() -{ - // Register to handle the scheme - mSchema.push_back( "rtsp" ); - mSchema.push_back( "rtmp" ); - - // Register to handle the category - mMimeTypeCategories.push_back( "video" ); - mMimeTypeCategories.push_back( "audio" ); -} - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplGStreamer:: -LLMediaImplGStreamer () : - mediaData ( NULL ), - mMediaRowbytes ( 1 ), - mTextureFormatPrimary ( LL_MEDIA_BGRA ), - mTextureFormatType ( LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV ), - mPump ( NULL ), - mPlaybin ( NULL ), - mVideoSink ( NULL ), - mLastTitle ( "" ), - mState( GST_STATE_NULL ), - mPlayThread ( NULL ) -{ - startup( NULL ); // Startup gstreamer if it hasn't been already. - - LL_DEBUGS("MediaManager") << "constructing media..." << LL_ENDL; - mVolume = -1.0; // XXX Hack to make the vould change happend first time - - setMediaDepth(4); - - // Create a pumpable main-loop for this media - mPump = g_main_loop_new (NULL, FALSE); - if (!mPump) - { - return; // error - } - - // instantiate a playbin element to do the hard work - mPlaybin = gst_element_factory_make ("playbin", "play"); - if (!mPlaybin) - { - // todo: cleanup pump - return; // error - } - - if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) - { - // instantiate and connect a custom video sink - LL_DEBUGS("MediaManager") << "extrenal video sink..." << LL_ENDL; - - // Plays inworld instead of in external player - mVideoSink = - GST_SLVIDEO(gst_element_factory_make ("private-slvideo", "slvideo")); - if (!mVideoSink) - { - LL_WARNS("MediaImpl") << "Could not instantiate private-slvideo element." << LL_ENDL; - // todo: cleanup. - return; // error - } - - g_object_set(mPlaybin, "video-sink", mVideoSink, (void*)NULL); - } -} - -// virtual -int LLMediaImplGStreamer::getTextureFormatPrimary() const -{ - return mTextureFormatPrimary; -} - -// virtual -int LLMediaImplGStreamer::getTextureFormatType() const -{ - return mTextureFormatType; -} - -// virtual -int LLMediaImplGStreamer::getTextureFormatInternal() const -{ - return LL_MEDIA_RGB8; -} - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplGStreamer:: -~LLMediaImplGStreamer () -{ - LL_DEBUGS("MediaImpl") << ("dtor of media...") << LL_ENDL; - unload(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -std::string LLMediaImplGStreamer::getVersion() -{ - guint major, minor, micro, nano; - gst_version(&major, &minor, µ, &nano); - std::string version = llformat("%d.%d.%d.%d",major,minor,micro,nano); - return version; -} - -// -// STARTUP -/////////////////////////////////////////////////////////////////////////////// -// (static) super-initialization - called once at application startup -bool LLMediaImplGStreamer::startup (LLMediaManagerData* init_data) -{ - static bool done_init = false; - if (!done_init) - { - // Init the glib type system - we need it. - g_type_init(); - - set_gst_plugin_path(); - - // Protect against GStreamer resetting the locale, yuck. - static std::string saved_locale; - saved_locale = setlocale(LC_ALL, NULL); - if (0 == gst_init_check(NULL, NULL, NULL)) - { - LL_WARNS("MediaImpl") << "GStreamer library failed to initialize and load standard plugins." << LL_ENDL; - setlocale(LC_ALL, saved_locale.c_str() ); - return false; - } - setlocale(LC_ALL, saved_locale.c_str() ); - - // Set up logging facilities - gst_debug_remove_log_function( gst_debug_log_default ); - gst_debug_add_log_function( gstreamer_log, NULL ); - - // Init our custom plugins - only really need do this once. - gst_slvideo_init_class(); - - - // List the plugins GStreamer can find - LL_DEBUGS("MediaImpl") << "Found GStreamer plugins:" << LL_ENDL; - GList *list; - GstRegistry *registry = gst_registry_get_default(); - std::string loaded = ""; - for (list = gst_registry_get_plugin_list(registry); - list != NULL; - list = g_list_next(list)) - { - GstPlugin *list_plugin = (GstPlugin *)list->data; - (bool)gst_plugin_is_loaded(list_plugin) ? loaded = "Yes" : loaded = "No"; - LL_DEBUGS("MediaImpl") << gst_plugin_get_name(list_plugin) << ", loaded? " << loaded << LL_ENDL; - } - gst_plugin_list_free(list); - - - done_init = true; - } - return true; -} - - -void LLMediaImplGStreamer::set_gst_plugin_path() -{ - // Linux sets GST_PLUGIN_PATH in wrapper.sh, not here. -#if LL_WINDOWS || LL_DARWIN - - std::string imp_dir = ""; - - // Get the current working directory: -#if LL_WINDOWS - char* raw_dir; - raw_dir = _getcwd(NULL,0); - if( raw_dir != NULL ) - { - imp_dir = std::string( raw_dir ); - } -#elif LL_DARWIN - CFBundleRef main_bundle = CFBundleGetMainBundle(); - if( main_bundle != NULL ) - { - CFURLRef bundle_url = CFBundleCopyBundleURL( main_bundle ); - if( bundle_url != NULL ) - { - #ifndef MAXPATHLEN - #define MAXPATHLEN 1024 - #endif - char raw_dir[MAXPATHLEN]; - if( CFURLGetFileSystemRepresentation( bundle_url, true, (UInt8 *)raw_dir, MAXPATHLEN) ) - { - imp_dir = std::string( raw_dir ) + "/Contents/MacOS/"; - } - CFRelease(bundle_url); - } - } -#endif - - if( imp_dir == "" ) - { - LL_WARNS("MediaImpl") << "Could not get application directory, not setting GST_PLUGIN_PATH." - << LL_ENDL; - return; - } - - LL_DEBUGS("MediaImpl") << "Imprudence is installed at " - << imp_dir << LL_ENDL; - - // ":" on Mac and 'Nix, ";" on Windows - std::string separator = G_SEARCHPATH_SEPARATOR_S; - - // Grab the current path, if it's set. - std::string old_plugin_path = ""; - char *old_path = getenv("GST_PLUGIN_PATH"); - if(old_path == NULL) - { - LL_DEBUGS("MediaImpl") << "Did not find user-set GST_PLUGIN_PATH." - << LL_ENDL; - } - else - { - old_plugin_path = separator + std::string( old_path ); - } - - - // Search both Imprudence and Imprudence\lib\gstreamer-plugins. - // But we also want to search the path the user has set, if any. - std::string plugin_path = -#if LL_WINDOWS - imp_dir + "\\lib\\gstreamer-plugins" + -#elif LL_DARWIN - imp_dir + separator + - imp_dir + "/../Resources/lib/gstreamer-plugins" + -#endif - old_plugin_path; - - int put_result; - - // Place GST_PLUGIN_PATH in the environment settings -#if LL_WINDOWS - put_result = _putenv_s( "GST_PLUGIN_PATH", (char*)plugin_path.c_str() ); -#elif LL_DARWIN - put_result = setenv( "GST_PLUGIN_PATH", (char*)plugin_path.c_str(), 1 ); -#endif - - if( put_result == -1 ) - { - LL_WARNS("MediaImpl") << "Setting GST_PLUGIN_PATH failed!" << LL_ENDL; - } - else - { - LL_DEBUGS("MediaImpl") << "GST_PLUGIN_PATH set to " - << getenv("GST_PLUGIN_PATH") << LL_ENDL; - } - - // Don't load system plugins. We only want to use ours, to avoid conflicts. -#if LL_WINDOWS - put_result = _putenv_s( "GST_PLUGIN_SYSTEM_PATH", "" ); -#elif LL_DARWIN - put_result = setenv( "GST_PLUGIN_SYSTEM_PATH", "", 1 ); -#endif - - if( put_result == -1 ) - { - LL_WARNS("MediaImpl") << "Setting GST_PLUGIN_SYSTEM_PATH=\"\" failed!" - << LL_ENDL; - } - -#endif // LL_WINDOWS || LL_DARWIN -} - - -void LLMediaImplGStreamer::gstreamer_log(GstDebugCategory *category, - GstDebugLevel level, - const gchar *file, - const gchar *function, - gint line, - GObject *object, - GstDebugMessage *message, - gpointer data) -{ - std::stringstream log(std::stringstream::out); - - // Log format example: - // - // GST_ELEMENT_PADS: removing pad 'sink' (in gstelement.c:757:gst_element_remove_pad) - // - log << gst_debug_category_get_name( category ) << ": " - << gst_debug_message_get(message) << " " - << "(in " << file << ":" << line << ":" << function << ")"; - - switch( level ) - { - case GST_LEVEL_ERROR: - LL_WARNS("MediaImpl") << "(ERROR) " << log.str() << LL_ENDL; - break; - case GST_LEVEL_WARNING: - LL_WARNS("MediaImpl") << log.str() << LL_ENDL; - break; - case GST_LEVEL_DEBUG: - LL_DEBUGS("MediaImpl") << log.str() << LL_ENDL; - break; - case GST_LEVEL_INFO: - LL_INFOS("MediaImpl") << log.str() << LL_ENDL; - break; - default: - // Do nothing. - break; - } -} - - -bool LLMediaImplGStreamer::closedown() -{ - return true; -} - - -bool LLMediaImplGStreamer::setDebugLevel( LLMediaBase::EDebugLevel level ) -{ - // Do parent class stuff. - LLMediaImplCommon::setDebugLevel(level); - - // Set GStreamer verbosity. - gst_debug_set_default_threshold( (GstDebugLevel)level ); - - return true; -} - - -/////////////////////////////////////////////////////////////////////////////// -// -// Uncomment the line below to enable spammy debug data. -//#define LL_GST_REPORT_STATE_CHANGES -#ifdef LL_GST_REPORT_STATE_CHANGES -static const char* get_gst_state_name(GstState state) -{ - switch (state) - { - case GST_STATE_VOID_PENDING: return "VOID_PENDING"; - case GST_STATE_NULL: return "NULL"; - case GST_STATE_READY: return "READY"; - case GST_STATE_PAUSED: return "PAUSED"; - case GST_STATE_PLAYING: return "PLAYING"; - } - return "(unknown)"; -} -#endif // LL_GST_REPORT_STATE_CHANGES - -//static -gboolean LLMediaImplGStreamer::bus_callback(GstBus *bus, GstMessage *message, gpointer data) -{ -#ifdef LL_GST_REPORT_STATE_CHANGES - LL_DEBUGS("MediaCallback") << "Got GST message type: " << GST_MESSAGE_TYPE_NAME (message) << LL_ENDL; -#endif - - LLMediaImplGStreamer *impl = (LLMediaImplGStreamer*)data; - - switch (GST_MESSAGE_TYPE (message)) - { - case GST_MESSAGE_BUFFERING: - { - gint percent = 0; - gst_message_parse_buffering(message, &percent); -#ifdef LL_GST_REPORT_STATE_CHANGES - LL_DEBUGS("MediaBuffering") << "GST buffering: " << percent << "%%" << LL_ENDL; -#endif - LLMediaEvent event( impl, percent ); - impl->getEventEmitter().update( &LLMediaObserver::onUpdateProgress, event ); - } - break; - case GST_MESSAGE_STATE_CHANGED: - { - GstState old_state; - GstState new_state; - GstState pending_state; - gst_message_parse_state_changed(message, - &old_state, - &new_state, - &pending_state); -#ifdef LL_GST_REPORT_STATE_CHANGES - // not generally very useful, and rather spammy. - LL_DEBUGS("MediaState") << "GST state change (old,,pending): "<< get_gst_state_name(old_state) << ",<" << get_gst_state_name(new_state) << ">," << get_gst_state_name(pending_state) << LL_ENDL; -#endif // LL_GST_REPORT_STATE_CHANGES - - switch (new_state) - { - case GST_STATE_VOID_PENDING: - break; - case GST_STATE_NULL: -#ifdef LL_GST_REPORT_STATE_CHANGES - LL_DEBUGS("MediaImpl") << "State changed to NULL" << LL_ENDL; -#endif - if (impl->getState() == GST_STATE_PLAYING) - { - // Stream was probably dropped, trying to restart - impl->play(); -#ifdef LL_GST_REPORT_STATE_CHANGES - LL_DEBUGS("MediaImpl") << "Trying to restart." << LL_ENDL; -#endif - } - break; - case GST_STATE_READY: - break; - case GST_STATE_PAUSED: - break; - case GST_STATE_PLAYING: - //impl->mLastTitle = ""; - - LLMediaEvent event( impl, 100 ); - impl->getEventEmitter().update( &LLMediaObserver::onUpdateProgress, event ); - // emit an event to say that a media source was loaded - LLMediaEvent event2( impl ); - impl->getEventEmitter().update( &LLMediaObserver::onMediaLoaded, event2 ); - break; - } - break; - } - case GST_MESSAGE_ERROR: - { - GError *err = NULL; - gchar *debug = NULL; - - gst_message_parse_error (message, &err, &debug); - LL_WARNS("MediaImpl") << "GST Error: " << err->message << LL_ENDL; - g_error_free (err); - g_free (debug); - - impl->addCommand(LLMediaBase::COMMAND_STOP); - //impl->addCommand(LLMediaBase::COMMAND_START); - - break; - } - case GST_MESSAGE_INFO: - { - GError *err = NULL; - gchar *debug = NULL; - - gst_message_parse_info (message, &err, &debug); - LL_INFOS("MediaImpl") << "GST info: " << err->message - << LL_ENDL; - g_error_free (err); - g_free (debug); - break; - } - case GST_MESSAGE_WARNING: - { - GError *err = NULL; - gchar *debug = NULL; - - gst_message_parse_warning (message, &err, &debug); - LL_WARNS("MediaImpl") << "GST warning: " << err->message - << LL_ENDL; - g_error_free (err); - g_free (debug); - - break; - } - case GST_MESSAGE_TAG: - { - GstTagList *new_tags; - - gst_message_parse_tag( message, &new_tags ); - - gchar *title; - - if ( gst_tag_list_get_string(new_tags, GST_TAG_TITLE, &title) ) - { - LL_INFOS("MediaInfo") << "Title: " << title << LL_ENDL; - std::string newtitle(title); - gst_tag_list_free(new_tags); - - if ( newtitle != impl->mLastTitle && newtitle != "" ) - { - impl->mLastTitle = newtitle; - LLMediaEvent event( impl, impl->mLastTitle ); - impl->getEventEmitter().update( &LLMediaObserver::onMediaTitleChange, event ); - } - - g_free(title); - } - - break; - } - case GST_MESSAGE_EOS: - { - /* end-of-stream */ - LL_DEBUGS("MediaImpl") << "GST end-of-stream." << LL_ENDL; - if (impl->isLooping()) - { - LL_DEBUGS("MediaImpl") << "looping media..." << LL_ENDL; - impl->stop(); - impl->play(); - } - else - { - // inject a COMMAND_STOP - impl->addCommand(LLMediaBase::COMMAND_STOP); - } - break; - } - default: - /* unhandled message */ - break; - } - /* we want to be notified again the next time there is a message - * on the bus, so return true (false means we want to stop watching - * for messages on the bus and our callback should not be called again) - */ - return TRUE; -} - -/////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplGStreamer::navigateTo (const std::string urlIn) -{ - LL_DEBUGS("MediaImpl") << "Setting media URI: " << urlIn.c_str() - << LL_ENDL; - - if (mPump == NULL || mPlaybin == NULL) - { - return false; - } - - setStatus( LLMediaBase::STATUS_NAVIGATING ); - - // set URI - g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), (void*)NULL); - - // get playbin's bus - perhaps this can/should be done in ctor - GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); - if (!bus) - { - return false; - } - gst_bus_add_watch (bus, bus_callback, this); - gst_object_unref (bus); - - mState = GST_STATE_READY; - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaImplGStreamer::unload() -{ - LL_DEBUGS("MediaImpl") << "unloading media..." << LL_ENDL; - if (mPlaybin) - { - gst_element_set_state (mPlaybin, GST_STATE_NULL); - mState = GST_STATE_NULL; - gst_object_unref (GST_OBJECT (mPlaybin)); - mPlaybin = NULL; - } - - if (mPump) - { - g_main_loop_quit(mPump); - mPump = NULL; - } - - if (mediaData) - { - delete [] mediaData; - mediaData = NULL; - } - - mVideoSink = NULL; - mState = GST_STATE_NULL; - setStatus(LLMediaBase::STATUS_UNKNOWN); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplGStreamer::updateMedia() -{ - //LL_DEBUGS("MediaImpl") << "updating media..." << LL_ENDL; - - // sanity check - if (mPump == NULL || mPlaybin == NULL) - { -#ifdef LL_GST_REPORT_STATE_CHANGES - LL_DEBUGS("MediaImpl") << "dead media..." << LL_ENDL; -#endif - mState = GST_STATE_NULL; - setStatus(LLMediaBase::STATUS_DEAD); - return false; - } - - if (mState == GST_STATE_VOID_PENDING || mState == GST_STATE_NULL) - return false; - - // process next outstanding command - switch (nextCommand()) - { - case LLMediaBase::COMMAND_START: - LL_DEBUGS("MediaImpl") << "COMMAND_START" << LL_ENDL; - if (getStatus() == LLMediaBase::STATUS_PAUSED || - getStatus() == LLMediaBase::STATUS_NAVIGATING || - getStatus() == LLMediaBase::STATUS_STOPPED) - { - play(); - setStatus(LLMediaBase::STATUS_STARTED); - clearCommand(); - } - break; - case LLMediaBase::COMMAND_STOP: - LL_DEBUGS("MediaImpl") << "COMMAND_STOP" << LL_ENDL; - stop(); - setStatus(LLMediaBase::STATUS_STOPPED); - clearCommand(); - break; - case LLMediaBase::COMMAND_PAUSE: - LL_DEBUGS("MediaImpl") << "COMMAND_PAUSE" << LL_ENDL; - if (getStatus() == LLMediaBase::STATUS_STARTED) - { - pause(); - setStatus(LLMediaBase::STATUS_PAUSED); - clearCommand(); - } - break; - default: - LL_INFOS("MediaImpl") << "Unknown command" << LL_ENDL; - clearCommand(); - break; - case LLMediaBase::COMMAND_NONE: - break; - } - - // deal with results - if (g_main_context_pending(g_main_loop_get_context(mPump))) - { - g_main_context_iteration(g_main_loop_get_context(mPump), FALSE); - } - - if (mVideoSink) - { - GST_OBJECT_LOCK(mVideoSink); - if (mVideoSink->retained_frame_ready) - { -#ifdef LL_GST_REPORT_STATE_CHANGES - LL_DEBUGS("MediaImpl") <<"NEW FRAME " << LL_ENDL; -#endif - if (mVideoSink->retained_frame_width != getMediaWidth() || - mVideoSink->retained_frame_height != getMediaHeight()) - // *TODO: also check for change in format - { - // just resize containe - int neww = mVideoSink->retained_frame_width; - int newh = mVideoSink->retained_frame_height; - int newd = SLVPixelFormatBytes[mVideoSink->retained_frame_format]; - if (SLV_PF_RGBX == mVideoSink->retained_frame_format) - { - mTextureFormatPrimary = LL_MEDIA_RGBA; - mTextureFormatType = LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV; - } - else - { - mTextureFormatPrimary = LL_MEDIA_BGRA; - mTextureFormatType = LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV; - } - mMediaRowbytes = neww * newd; - LL_DEBUGS("MediaImpl") - << "video container resized to " << - neww <<"x"<< newh << LL_ENDL; - - delete[] mediaData; - mediaData = new unsigned char[mMediaRowbytes * - newh]; - - GST_OBJECT_UNLOCK(mVideoSink); - - setMediaDepth(newd); - setMediaSize(neww, newh); - return true; - } - - // we're gonna totally consume this frame - reset 'ready' flag - mVideoSink->retained_frame_ready = FALSE; - memcpy(mediaData, mVideoSink->retained_frame_data, - mMediaRowbytes * getMediaHeight()); - - GST_OBJECT_UNLOCK(mVideoSink); - LLMediaEvent event( this ); - mEventEmitter.update( &LLMediaObserver::onMediaContentsChange, event ); - return true; - } - else - { - // nothing to do yet. - GST_OBJECT_UNLOCK(mVideoSink); - return true; - } - } - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaImplGStreamer::stop() -{ - LL_DEBUGS("MediaImpl") << "attempting to stop..." << LL_ENDL; - - if (!mPlaybin || mState == GST_STATE_NULL) - return true; - - GstStateChangeReturn state_change; - - state_change = gst_element_set_state(mPlaybin, GST_STATE_READY); - - LL_DEBUGS("MediaImpl") << gst_element_state_change_return_get_name(state_change) << LL_ENDL; - - if (state_change == GST_STATE_CHANGE_FAILURE) - { - LL_WARNS("MediaImpl") << "could not stop stream!" << LL_ENDL; - return false; - } - else - { - // Going into pending after play keeps dead streams from looping - (mState == GST_STATE_PLAYING) ? (mState = GST_STATE_VOID_PENDING) : (mState = GST_STATE_READY); - return true; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaImplGStreamer::play() -{ - LL_DEBUGS("MediaImpl") << "attempting to play..." << LL_ENDL; - - if (!mPlaybin || mState == GST_STATE_NULL) - return true; - - - if( getState() == GST_STATE_PLAYING ) - { - LL_DEBUGS("MediaImpl") << "... but already playing." << LL_ENDL; - return true; - } - - // Clean up the existing thread, if any. - if( mPlayThread != NULL && mPlayThread->isStopped()) - { - delete mPlayThread; - mPlayThread = NULL; - } - - if( mPlayThread == NULL ) - { - // Make a new thread to start playing. This keeps the viewer - // responsive while the stream is resolved and buffered. - mPlayThread = new LLGstPlayThread( (LLMediaImplCommon *)this, "GstPlayThread", NULL); - mPlayThread->start(); - } - - return true; -} - - -void LLMediaImplGStreamer::startPlay() -{ - GstStateChangeReturn state_change; - - state_change = gst_element_set_state(mPlaybin, GST_STATE_PLAYING); - mState = GST_STATE_PLAYING; - - LL_DEBUGS("MediaImpl") << gst_element_state_change_return_get_name(state_change) << LL_ENDL; - - // Check to make sure playing was successful. If not, stop. - // NOTE: state_change is almost always GST_STATE_CHANGE_ASYNC - if (state_change == GST_STATE_CHANGE_FAILURE) - { - // If failing from a bad stream, go into an unknown - // state to stop bus_callback from looping back. - // We also force a stop in case the operations don't sync - setStatus(LLMediaBase::STATUS_UNKNOWN); - stop(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaImplGStreamer::pause() -{ - LL_DEBUGS("MediaImpl") << "attempting to pause..." << LL_ENDL; - - if (!mPlaybin || mState == GST_STATE_NULL) - return true; - - GstStateChangeReturn state_change; - - state_change = gst_element_set_state(mPlaybin, GST_STATE_PAUSED); - - LL_DEBUGS("MediaImpl") << gst_element_state_change_return_get_name(state_change) << LL_ENDL; - - if (state_change == GST_STATE_CHANGE_FAILURE) - { - LL_WARNS("MediaImpl") << "could not pause stream!" << LL_ENDL; - return false; - } - else - { - mState = GST_STATE_PAUSED; - return true; - } -}; - - -/////////////////////////////////////////////////////////////////////////////// -// virtual -unsigned char* LLMediaImplGStreamer::getMediaData() -{ - return mediaData; -} - - -/////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplGStreamer::seek(double time) -{ - bool success = false; - if (mPlaybin) - { - success = gst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, - GstSeekFlags(GST_SEEK_FLAG_FLUSH | - GST_SEEK_FLAG_KEY_UNIT), - GST_SEEK_TYPE_SET, gint64(time*1000000000.0F), - GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); - } - LL_DEBUGS("MediaImpl") << "MEDIA SEEK REQUEST to " << float(time) - << "sec result was " << int(success) << LL_ENDL; - return success; -} - - -/////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplGStreamer::setVolume(float volume) -{ - // we try to only update volume as conservatively as - // possible, as many gst-plugins-base versions up to at least - // November 2008 have critical race-conditions in setting volume - sigh - if (mVolume == volume) - return true; // nothing to do, everything's fine - - mVolume = volume; - if (mPlaybin) - { - g_object_set(mPlaybin, "volume", mVolume, (void*)NULL); - return true; - } - - return false; -} - - - -///#endif // LL_GSTREAMER_ENABLED diff --git a/linden/indra/llmedia/llmediaimplgstreamer.h b/linden/indra/llmedia/llmediaimplgstreamer.h deleted file mode 100644 index 8d2e75675..000000000 --- a/linden/indra/llmedia/llmediaimplgstreamer.h +++ /dev/null @@ -1,164 +0,0 @@ -/** - * @file llmediaimplgstreamer.h - * @author Tofu Linden - * @brief implementation that supports media playback via GStreamer. - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -// header guard -#ifndef llmediaimplgstreamer_h -#define llmediaimplgstreamer_h - -#include "llmediaimplcommon.h" -#include "llmediaimplfactory.h" - -///#if LL_GSTREAMER_ENABLED - -extern "C" { -#include -} - -#include -#include "apr_pools.h" -#include "apr_dso.h" - - -#include "llmediaimplgstreamervidplug.h" -#include "llgstplaythread.h" - -class LLMediaManagerData; -class LLMediaImplMaker; - -/////////////////////////////////////////////////////////////////////////// -class LLMediaImplGStreamer: - public LLMediaImplCommon -{ - friend class LLGstPlayThread; - - public: - LLMediaImplGStreamer (); - virtual ~LLMediaImplGStreamer (); - - //////////////////////////////////////////////////////// - // implementation of the media public interface - - static bool startup( LLMediaManagerData* init_data ); - static bool closedown(); - - // Sets GST_PLUGIN_PATH env var for GStreamer. - static void set_gst_plugin_path(); - - /* virtual */ bool setDebugLevel( LLMediaBase::EDebugLevel level ); - - // Function given to GStreamer for handling debug messages - static void gstreamer_log(GstDebugCategory *category, - GstDebugLevel level, - const gchar *file, - const gchar *function, - gint line, - GObject *object, - GstDebugMessage *message, - gpointer data) -#if __GNUC__ - // recommended by the gstreamer docs - G_GNUC_NO_INSTRUMENT -#endif - ; - - /* virtual */ std::string getVersion(); - /* virtual */ bool navigateTo( const std::string url ); - /* virtual */ bool updateMedia(); - /* virtual */ unsigned char* getMediaData(); - /* virtual */ int getTextureFormatPrimary() const; - /* virtual */ int getTextureFormatType() const; - /* virtual */ int getTextureFormatInternal() const; - /* virtual */ bool seek( double time ); - /* virtual */ bool setVolume( float volume ); - - LLMediaEmitter< LLMediaObserver > getEventEmitter() const {return mEventEmitter;}; - - protected: - - void startPlay(); - - - private: - - // misc - bool unload(); - bool pause(); - bool stop(); - bool play(); - - static gboolean bus_callback (GstBus *bus, - GstMessage *message, - gpointer data); - - unsigned char* mediaData; - int mMediaRowbytes; - int mTextureFormatPrimary; - int mTextureFormatType; - - // GStreamer-specific - GMainLoop *mPump; // event pump for this media - GstElement *mPlaybin; - GstSLVideo *mVideoSink; - std::string mLastTitle; - GstState mState; - GstState getState() const { return mState; } - - LLGstPlayThread *mPlayThread; -}; - -class LLMediaImplGStreamerMaker : public LLMediaImplMaker -{ - public: - LLMediaImplGStreamerMaker(); - LLMediaImplGStreamer* create() - { - return new LLMediaImplGStreamer(); - } -}; - -///////////////////////////////////////////////////////////////////////// -// Debug/Info/Warning macros. -#define STDERRMSG(...) do{\ - fprintf(stderr, "%s:%d: ", __FUNCTION__, __LINE__);\ - fprintf(stderr, __VA_ARGS__);\ - fputc('\n',stderr);\ - }while(0) -#define NULLMSG(...) do{}while(0) - -#define DEBUGMSG NULLMSG -#define INFOMSG STDERRMSG -#define WARNMSG STDERRMSG -///////////////////////////////////////////////////////////////////////// - -///#endif // LL_GSTREAMER_ENABLED - -#endif // llmediaimplgstreamer_h diff --git a/linden/indra/llmedia/llmediaimplllmozlib.cpp b/linden/indra/llmedia/llmediaimplllmozlib.cpp deleted file mode 100644 index 5b4b02ebe..000000000 --- a/linden/indra/llmedia/llmediaimplllmozlib.cpp +++ /dev/null @@ -1,624 +0,0 @@ -/** - * @file llmediaimplllmozlib.cpp - * @brief Example 2 of a media impl concrete class - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llmediaimplllmozlib.h" - -#if LL_LLMOZLIB_ENABLED - -#include "llmediaimplregister.h" -#include "llmediamanager.h" - -#ifdef WIN32 - // platform specific includes needed before OpenGL header - #include - #include -#elif defined(__APPLE__) - // framework-style include path when building on the Mac. - #include -#else // Assume this is linux - // Linux, MESA headers, but not necessarily assuming MESA runtime. - // quotes so we get libraries/.../GL/ version - #include "GL/gl.h" -#endif - - -#include - - -#include - -// register this impl with media manager factory -static LLMediaImplRegister sLLMediaImplLLMozLibReg( "LLMediaImplLLMozLib", new LLMediaImplLLMozLibMaker() ); - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplLLMozLibMaker::LLMediaImplLLMozLibMaker() -{ - // Register to handle the mime category - mMimeTypes.push_back( "image/svg+xml" ); - mMimeTypeCategories.push_back( "text" ); -#if !LL_QUICKTIME_ENABLED - mMimeTypeCategories.push_back( "image" ); -#endif -} - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplLLMozLib::LLMediaImplLLMozLib() : - mBrowserWindowWidth( 800 ), - mBrowserWindowHeight( 600 ), - mMediaDataWidth( 0 ), - mMediaDataHeight( 0 ), - mWindowId( 0 ), - mNeedsUpdate( false ) -{ - setRequestedMediaSize( mBrowserWindowWidth, mBrowserWindowHeight ); - - setMediaDepth( 4 ); -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) super-initialization - called once at application startup -bool LLMediaImplLLMozLib::startup( LLMediaManagerData* init_data ) -{ - - // Yuck, Mozilla's GTK callbacks play with the locale - push/pop - // the locale to protect it, as exotic/non-C locales - // causes our code lots of general critical weirdness - // and crashness. (SL-35450) - static std::string saved_locale; - saved_locale = setlocale(LC_ALL, NULL); - - - bool result = LLMozLib::getInstance()->init( init_data->getBrowserApplicationDir(), - init_data->getBrowserComponentDir(), - init_data->getBrowserProfileDir(), - init_data->getBrowserParentWindow() ); - - - setlocale(LC_ALL, saved_locale.c_str() ); - - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) super-uninitialization - called once at application closedown -bool LLMediaImplLLMozLib::closedown() -{ - // name discrepancy - this reset actually shuts down LLMozLib - LLMozLib::getInstance()->reset(); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) -bool LLMediaImplLLMozLib::setBrowserUserAgent(std::string user_agent) -{ - // append special string to the embedded browser user agent string - LLMozLib::getInstance()->setBrowserAgentId(user_agent); - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::init() -{ - // if mWindowId is non-0, it's we already called init() and shouldn't call it again - // (::reset() will zero this value) - if ( mWindowId ) - return false; - -#if defined(LL_LINUX) || defined(WIN32) - static std::string saved_locale; - saved_locale = setlocale(LC_ALL, NULL); -#endif // defined(LL_LINUX) || defined(WIN32) - - mWindowId = LLMozLib::getInstance()->createBrowserWindow( mBrowserWindowWidth, mBrowserWindowHeight ); - - LLMozLib::getInstance()->setSize( mWindowId, mBrowserWindowWidth, mBrowserWindowHeight ); - - LLMozLib::getInstance()->setBackgroundColor( mWindowId, 0x00, 0x00, 0x00 ); - - LLMozLib::getInstance()->addObserver( mWindowId, this ); - - // plugins only work with some client-side hackery and they cause - // exception handling issues (DEV-10020) so we turn them off - LLMozLib::getInstance()->enablePlugins( false ); - - // second life client needs the bitmap flipped - LLMozLib::getInstance()->flipWindow( mWindowId, true ); - - // set media depth now we have created a browser window and know what it is - setMediaDepth( LLMozLib::getInstance()->getBrowserDepth( mWindowId ) ); - -#if defined(LL_LINUX) || defined(WIN32) - setlocale(LC_ALL, saved_locale.c_str() ); -#endif // defined(LL_LINUX) || defined(WIN32) - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -std::string LLMediaImplLLMozLib::getVersion() -{ - std::string version_string = "[" + sLLMediaImplLLMozLibReg.getImplName() + "] - " + LLMozLib::getInstance()->getVersion(); - - return version_string; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::set404RedirectUrl( std::string redirect_url ) -{ - return LLMozLib::getInstance()->set404RedirectUrl( mWindowId, redirect_url ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual - -bool LLMediaImplLLMozLib::clr404RedirectUrl() -{ - return LLMozLib::getInstance()->clr404RedirectUrl( mWindowId ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::setBackgroundColor( unsigned int red, unsigned int green, unsigned int blue ) const -{ - return LLMozLib::getInstance()->setBackgroundColor( mWindowId, red, green, blue ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::setCaretColor( unsigned int red, unsigned int green, unsigned int blue ) const -{ - return LLMozLib::getInstance()->setCaretColor( mWindowId, red, green, blue ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::navigateTo( const std::string url ) -{ - // pass url to llmozlib - LLMozLib::getInstance()->navigateTo( mWindowId, url ); - - // emit event with size change to kick things off - LLMediaEvent event( this ); - mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); - - // not that useful right now but maybe later - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::updateMedia() -{ - if ( getStatus() == LLMediaBase::STATUS_STARTED ) - { - // if flag set, the page changed and we need to update - if ( mNeedsUpdate ) - { - // snap browser pixels - LLMozLib::getInstance()->grabBrowserWindow( mWindowId ); - - // update media width - rendering the page can change it - mMediaDataWidth = LLMozLib::getInstance()->getBrowserRowSpan( mWindowId ) / getMediaDepth(); - mMediaDataHeight = LLMozLib::getInstance()->getBrowserHeight( mWindowId ); - - // emit an event to say that something in the media stream changed - LLMediaEvent event( this ); - mEventEmitter.update( &LLMediaObserver::onMediaContentsChange, event ); - - // flag that we've done the update and one isn't needed next frame - mNeedsUpdate = false; - }; - }; - - // update the state (e.g. transport controls) state - updateState(); - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaImplLLMozLib::updateState() -{ - if ( nextCommand() == LLMediaBase::COMMAND_START ) - { - setStatus( LLMediaBase::STATUS_STARTED ); - clearCommand(); - }; - - if ( nextCommand() == LLMediaBase::COMMAND_STOP ) - { - setStatus( LLMediaBase::STATUS_STOPPED ); - clearCommand(); - }; - - if ( nextCommand() == LLMediaBase::COMMAND_BACK ) - { - setStatus( LLMediaBase::STATUS_STARTED ); - LLMozLib::getInstance()->navigateBack( mWindowId ); - clearCommand(); - }; - - if ( nextCommand() == LLMediaBase::COMMAND_FORWARD ) - { - setStatus( LLMediaBase::STATUS_STARTED ); - LLMozLib::getInstance()->navigateForward( mWindowId ); - clearCommand(); - }; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLMediaImplLLMozLib::onPageChanged( const EventType& eventIn ) -{ - // force an update when the contents of the page changes - mNeedsUpdate = true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLMediaImplLLMozLib::onClickLinkHref( const EventType& eventIn ) -{ - LLMediaEvent event( this, eventIn.getStringValue(), eventIn.getStringValue2() ); - mEventEmitter.update( &LLMediaObserver::onClickLinkHref, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLMediaImplLLMozLib::onClickLinkNoFollow( const EventType& eventIn ) -{ - LLMediaEvent event( this, eventIn.getStringValue() ); - mEventEmitter.update( &LLMediaObserver::onClickLinkNoFollow, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLMediaImplLLMozLib::onUpdateProgress( const EventType& eventIn ) -{ - LLMediaEvent event( this, eventIn.getIntValue() ); - mEventEmitter.update( &LLMediaObserver::onUpdateProgress, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLMediaImplLLMozLib::onStatusTextChange( const EventType& eventIn ) -{ - LLMediaEvent event( this, eventIn.getStringValue() ); - mEventEmitter.update( &LLMediaObserver::onStatusTextChange, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLMediaImplLLMozLib::onLocationChange( const EventType& eventIn ) -{ - LLMediaEvent event( this, eventIn.getEventUri() ); - mEventEmitter.update( &LLMediaObserver::onLocationChange, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLMediaImplLLMozLib::onNavigateBegin( const EventType& eventIn ) -{ - LLMediaEvent event( this, eventIn.getEventUri() ); - mEventEmitter.update( &LLMediaObserver::onNavigateBegin, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLMediaImplLLMozLib::onNavigateComplete( const EventType& eventIn ) -{ - // force an update when the page is finished - mNeedsUpdate = true; - - // pass in url and HTML response code (200/404 etc.) - LLMediaEvent event( this, eventIn.getEventUri(), eventIn.getIntValue() ); - mEventEmitter.update( &LLMediaObserver::onNavigateComplete, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -unsigned char* LLMediaImplLLMozLib::getMediaData() -{ - return (unsigned char*)LLMozLib::getInstance()->getBrowserWindowPixels( mWindowId ); -} - -// helper func to compute size of media data -bool LLMediaImplLLMozLib::recomputeSizes() -{ - int new_width = mMediaRequestedWidth; - int new_height = mMediaRequestedHeight; - - if (new_width < 0) - new_width = 512; - - if (new_height < 0) - new_height = 512; - - if (mAutoScaled) - { - new_width = LLMediaManager::textureWidthFromMediaWidth( new_width ); - new_height = LLMediaManager::textureHeightFromMediaHeight( new_height ); - } - - bool status = LLMozLib::getInstance()->setSize( mWindowId, new_width, new_height ); - - if (status) - setMediaSize(new_width, new_height); - - return status; -} - - -//////////////////////////////////////////////////////////////////////////////// -// virtual -int LLMediaImplLLMozLib::getMediaDataWidth() const -{ - return mMediaDataWidth; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -int LLMediaImplLLMozLib::getMediaDataHeight() const -{ - return mMediaDataHeight; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::setRequestedMediaSize(int width, int height) -{ - LLMediaImplCommon::setRequestedMediaSize(width, height); - - return recomputeSizes(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::setAutoScaled( bool auto_scaled ) -{ - LLMediaImplCommon::setAutoScaled(auto_scaled); - - return recomputeSizes(); -} - - -//////////////////////////////////////////////////////////////////////////////// -// virtual -int LLMediaImplLLMozLib::getTextureFormatPrimary() const -{ -#if defined(__APPLE__) || defined(MACOSX) - return GL_BGRA_EXT; -#else - return LLMozLib::getInstance()->getBrowserDepth( mWindowId ) == 3 ? GL_BGR_EXT : GL_BGRA_EXT; -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -int LLMediaImplLLMozLib::getTextureFormatType() const -{ -#if defined(__APPLE__) || defined(MACOSX) - #ifdef __BIG_ENDIAN__ - return GL_UNSIGNED_INT_8_8_8_8_REV; - #else - return GL_UNSIGNED_INT_8_8_8_8; - #endif -#else - return GL_UNSIGNED_BYTE; -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::mouseDown( int x_pos, int y_pos ) -{ - return LLMozLib::getInstance()->mouseDown( mWindowId, x_pos, y_pos ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::mouseUp( int x_pos, int y_pos ) -{ - LLMozLib::getInstance()->mouseUp( mWindowId, x_pos, y_pos ); - - // this seems better than sending focus on mouse down (still need to improve this) - LLMozLib::getInstance()->focusBrowser( mWindowId, true ); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::mouseMove( int x_pos, int y_pos ) -{ - return LLMozLib::getInstance()->mouseMove( mWindowId, x_pos, y_pos ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::keyPress( int key_code ) -{ - // We don't have to deal with printable characters here - they should - // go through handleUnicodeChar(). This table could be more complete - // than it is, but I think this covers all of the important - // non-printables. - - unsigned long moz_key; - - switch(key_code) - { - case LL_MEDIA_KEY_BACKSPACE: - moz_key = LL_DOM_VK_BACK_SPACE; break; - case LL_MEDIA_KEY_TAB: - moz_key = LL_DOM_VK_TAB; break; - case LL_MEDIA_KEY_RETURN: - moz_key = LL_DOM_VK_RETURN; break; - case LL_MEDIA_KEY_PAD_RETURN: - moz_key = LL_DOM_VK_ENTER; break; - case LL_MEDIA_KEY_ESCAPE: - moz_key = LL_DOM_VK_ESCAPE; break; - case LL_MEDIA_KEY_PAGE_UP: - moz_key = LL_DOM_VK_PAGE_UP; break; - case LL_MEDIA_KEY_PAGE_DOWN: - moz_key = LL_DOM_VK_PAGE_DOWN; break; - case LL_MEDIA_KEY_END: - moz_key = LL_DOM_VK_END; break; - case LL_MEDIA_KEY_HOME: - moz_key = LL_DOM_VK_HOME; break; - case LL_MEDIA_KEY_LEFT: - moz_key = LL_DOM_VK_LEFT; break; - case LL_MEDIA_KEY_UP: - moz_key = LL_DOM_VK_UP; break; - case LL_MEDIA_KEY_RIGHT: - moz_key = LL_DOM_VK_RIGHT; break; - case LL_MEDIA_KEY_DOWN: - moz_key = LL_DOM_VK_DOWN; break; - case LL_MEDIA_KEY_INSERT: - moz_key = LL_DOM_VK_INSERT; break; - case LL_MEDIA_KEY_DELETE: - moz_key = LL_DOM_VK_DELETE; break; - - default: - return false; // don't know how to map this key. - } - - return LLMozLib::getInstance()->keyPress( mWindowId, moz_key ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::scrollByLines( int lines ) -{ - return LLMozLib::getInstance()->scrollByLines(mWindowId, lines); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::focus( bool focus ) -{ - return LLMozLib::getInstance()->focusBrowser(mWindowId, focus); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::unicodeInput( unsigned long uni_char ) -{ - return LLMozLib::getInstance()->unicodeInput(mWindowId, uni_char); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::mouseLeftDoubleClick( int x_pos, int y_pos ) -{ - return LLMozLib::getInstance()->mouseLeftDoubleClick( mWindowId, x_pos, y_pos ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::navigateForward() -{ - return LLMozLib::getInstance()->navigateForward(mWindowId); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::navigateBack() -{ - return LLMozLib::getInstance()->navigateBack(mWindowId); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::canNavigateForward() -{ - return LLMozLib::getInstance()->canNavigateForward(mWindowId); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::canNavigateBack() -{ - return LLMozLib::getInstance()->canNavigateBack(mWindowId); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::enableCookies(bool enable) -{ - return LLMozLib::getInstance()->enableCookies(enable); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::enableProxy(bool enable, std::string proxy_host_name, int proxy_port) -{ - return LLMozLib::getInstance()->enableProxy(enable, proxy_host_name, proxy_port); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::clearCache() -{ - return LLMozLib::getInstance()->clearCache(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::clearCookies() -{ - return LLMozLib::getInstance()->clearAllCookies(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplLLMozLib::reset() -{ - LLMozLib::getInstance()->remObserver( mWindowId, this ); - - LLMozLib::getInstance()->destroyBrowserWindow( mWindowId ); - - mWindowId = 0; - - return true; -} - -#endif // LL_LLMOZLIB_ENABLED diff --git a/linden/indra/llmedia/llmediaimplllmozlib.h b/linden/indra/llmedia/llmediaimplllmozlib.h deleted file mode 100644 index f71300e4c..000000000 --- a/linden/indra/llmedia/llmediaimplllmozlib.h +++ /dev/null @@ -1,127 +0,0 @@ -/** - * @file llmediaimplllmozlib.cpp - * @brief Example 2 of a media impl concrete class - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLMEDIAIMPLLLMOZLIB_H -#define LLMEDIAIMPLLLMOZLIB_H - -#include "llmediaimplcommon.h" -#include "llmediaimplfactory.h" - -#if LL_LLMOZLIB_ENABLED - -#include "llmozlib2.h" - -class LLMediaManagerData; - -class LLMediaImplLLMozLib : - public LLMediaImplCommon, - public LLEmbeddedBrowserWindowObserver -{ - public: - LLMediaImplLLMozLib(); - - static bool startup( LLMediaManagerData* init_data ); - static bool closedown(); - - // Update the user-agent string reported when the browser requests - // web page, because we need to include the Second Life version - // and skin name (which can change without restarts). - // Must be called after startup(). - static bool setBrowserUserAgent(std::string user_agent); - - /* virtual */ bool init(); - /* virtual */ std::string getVersion(); - /* virtual */ bool set404RedirectUrl( std::string redirect_url ); - /* virtual */ bool clr404RedirectUrl(); - /* virtual */ bool setBackgroundColor( unsigned int red, unsigned int green, unsigned int blue ) const; - /* virtual */ bool setCaretColor( unsigned int red, unsigned int green, unsigned int blue ) const; - /* virtual */ bool navigateTo( const std::string url ); - /* virtual */ bool updateMedia(); - /* virtual */ unsigned char* getMediaData(); - /* virtual */ int getMediaDataWidth() const; - /* virtual */ int getMediaDataHeight() const; - /* virtual */ bool setRequestedMediaSize(int width, int height); - /* virtual */ bool setAutoScaled( bool auto_scaled ); - /* virtual */ int getTextureFormatPrimary() const; - /* virtual */ int getTextureFormatType() const; - /* virtual */ bool mouseDown( int x_pos, int y_pos ); - /* virtual */ bool mouseUp( int x_pos, int y_pos ); - /* virtual */ bool mouseMove( int x_pos, int y_pos ); - /* virtual */ bool keyPress( int key_code ); - /* virtual */ bool scrollByLines( int lines ); - /* virtual */ bool focus( bool focus ); - /* virtual */ bool unicodeInput( unsigned long uni_char ); - /* virtual */ bool mouseLeftDoubleClick( int x_pos, int y_pos ); - /* virtual */ bool navigateForward(); - /* virtual */ bool navigateBack(); - /* virtual */ bool canNavigateForward(); - /* virtual */ bool canNavigateBack(); - /* virtual */ bool enableCookies(bool enable); - /* virtual */ bool enableProxy(bool enable, std::string proxy_host_name, int proxy_port); - /* virtual */ bool clearCache(); - /* virtual */ bool clearCookies(); - /* virtual */ bool reset(); - - // LLMozLib observerables - virtual void onNavigateBegin( const EventType& eventIn ); - virtual void onNavigateComplete( const EventType& eventIn ); - virtual void onUpdateProgress( const EventType& eventIn ); - virtual void onPageChanged( const EventType& eventIn ); - virtual void onStatusTextChange( const EventType& eventIn ); - virtual void onLocationChange( const EventType& eventIn ); - virtual void onClickLinkHref( const EventType& eventIn ); - virtual void onClickLinkNoFollow( const EventType& eventIn ); - - private: - bool recomputeSizes(); - int mWindowId; - int mBrowserWindowWidth; - int mBrowserWindowHeight; - int mMediaDataWidth; - int mMediaDataHeight; - bool mNeedsUpdate; - bool updateState(); -}; - -// The maker class -class LLMediaImplLLMozLibMaker : public LLMediaImplMaker -{ - public: - LLMediaImplLLMozLibMaker(); - LLMediaImplLLMozLib* create() - { - return new LLMediaImplLLMozLib(); - } -}; -#endif // LL_LLMOZLIB_ENABLED - -#endif // LLMEDIAIMPLLLMOZLIB_H diff --git a/linden/indra/llmedia/llmediaimplquicktime.cpp b/linden/indra/llmedia/llmediaimplquicktime.cpp deleted file mode 100644 index 76cacee97..000000000 --- a/linden/indra/llmedia/llmediaimplquicktime.cpp +++ /dev/null @@ -1,657 +0,0 @@ -/** - * @file llmediaimplquicktime.cpp - * @brief QuickTime media impl concrete class - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llmediaimplquicktime.h" - -#if LL_QUICKTIME_ENABLED - -#include "llmediamanager.h" -#include "llmediaimplregister.h" - -#if LL_WINDOWS -#include -#endif - -#include -#include - -// register this impl with media manager factory -static LLMediaImplRegister sLLMediaImplQuickTimeReg( "LLMediaImplQuickTime", new LLMediaImplQuickTimeMaker() ); - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplQuickTimeMaker::LLMediaImplQuickTimeMaker() -{ - // Register to handle the scheme - mSchema.push_back( "rtsp" ); - - // Register to handle the category - mMimeTypeCategories.push_back( "video" ); - mMimeTypeCategories.push_back( "audio" ); - mMimeTypeCategories.push_back( "image" ); -} - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplQuickTime::LLMediaImplQuickTime() : - mMovieHandle( 0 ), - mGWorldHandle( 0 ), - mMovieController( 0 ), - mMinWidth( 32 ), - mMaxWidth( 2048 ), - mMinHeight( 32 ), - mMaxHeight( 2048 ), - mCurVolume( 0 ) -{ -} - -/////////////////////////////////////////////////////////////////////////////// -// -LLMediaImplQuickTime::~LLMediaImplQuickTime() -{ - unload(); -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) super-initialization - called once at application startup -bool LLMediaImplQuickTime::startup( LLMediaManagerData* init_data ) -{ -#ifdef WIN32 - if ( InitializeQTML( 0L ) != noErr ) - { - return false; - }; -#endif - - EnterMovies(); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) super-uninitialization - called once at application closedown -bool LLMediaImplQuickTime::closedown() -{ - ExitMovies(); - -#ifdef WIN32 - TerminateQTML(); -#endif - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// private -bool LLMediaImplQuickTime::load( const std::string url ) -{ - if ( url.empty() ) - return false; - - //In case std::string::c_str() makes a copy of the url data, - //make sure there is memory to hold it before allocating memory for handle. - //if fails, NewHandleClear(...) should return NULL. - const char* url_string = url.c_str() ; - Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) ); - if ( NULL == handle ) - return false; - if(noErr != MemError() || NULL == *handle) - { - return false ; - } - - BlockMove( url_string, *handle, ( Size )( url.length() + 1 ) ); - - //std::cout << "LLMediaImplQuickTime::load( " << url << " )" << std::endl; - - // TODO: supposed to use NewMovieFromDataParams now - OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType ); - DisposeHandle( handle ); - if ( noErr != err ) - return false; - - // do pre-roll actions (typically fired for streaming movies but not always) - PrePrerollMovie( mMovieHandle, 0, GetMoviePreferredRate( mMovieHandle ), moviePrePrerollCompleteCallback, ( void * )this ); - - // get movie rect (and check for min/max) - Rect movie_rect; - setMovieBoxEnhanced( &movie_rect ); - - // make a new movie controller - mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie ); - -#if defined(__APPLE__) || defined(MACOSX) - setMediaDepth( 4 ); -#else - setMediaDepth( 3 ); -#endif - - // tell manager about the media size - setMediaSize( movie_rect.right - movie_rect.left, movie_rect.bottom - movie_rect.top); - - // movie controller - MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this ); - - SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize ); - - // function that gets called when a frame is drawn - SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this ); - - // emit an event to say that a media source was loaded - LLMediaEvent event( this ); - mEventEmitter.update( &LLMediaObserver::onMediaLoaded, event ); - - // set up inital state - sizeChanged(); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -std::string LLMediaImplQuickTime::getVersion() -{ - long version; - Gestalt( gestaltQuickTimeVersion, &version ); - - std::ostringstream codec( "" ); - codec << "["; - codec << sLLMediaImplQuickTimeReg.getImplName(); - codec << "] - "; - codec << "QuickTime: " << std::hex << version; - - return codec.str(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplQuickTime::navigateTo( const std::string url ) -{ - // tell engine what we're doing - setStatus( LLMediaBase::STATUS_NAVIGATING ); - - // remove the movie we were looking at - unload(); - - // load the new one (no real 'go to this url' function in QT) - load( url ); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplQuickTime::sizeChanged() -{ - if ( ! mMovieHandle ) - return false; - - // sanitize size of movie - Rect movie_rect; - setMovieBoxEnhanced( &movie_rect ); - - // we need this later - int width = ( movie_rect.right - movie_rect.left ); - int height = ( movie_rect.bottom - movie_rect.top ); - - std::cout << "LLMEDIA> size changed to " << width << " x " << height << std::endl; - - setMediaSize( width, height ); - - // media depth won't change - int depth_bits = getMediaDepth() * 8; - - GWorldPtr old_gworld_handle = mGWorldHandle; - - if (old_gworld_handle) - { - GWorldFlags result = UpdateGWorld( &mGWorldHandle, depth_bits, &movie_rect, NULL, NULL, 0 ); - if ( gwFlagErr == result ) - { - // TODO: unrecoverable?? throw exception? return something? - return false; - } - } - else - { - OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &movie_rect, NULL, NULL, keepLocal | pixelsLocked ); - if ( noErr != result ) - { - // ATODO: unrecoverable?? throw exception? return something? - return false; - } - - // clear memory in GWorld to avoid random screen visual fuzz from uninitialized texture data - if ( mGWorldHandle ) - { - PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle ); - unsigned char* ptr = ( unsigned char* )GetPixBaseAddr( pix_map_handle ); - memset( ptr, 0x00, height * QTGetPixMapHandleRowBytes( pix_map_handle ) ); - } - } - - // point movie at GWorld if it's new - if ( mMovieHandle && ! old_gworld_handle ) - { - SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice ( mGWorldHandle ) ); - } - - // update movie controller - if ( mMovieController ) - { - MCSetControllerPort( mMovieController, mGWorldHandle ); - MCPositionController( mMovieController, &movie_rect, &movie_rect, - mcTopLeftMovie | mcPositionDontInvalidate ); - MCMovieChanged( mMovieController, mMovieHandle ); - } - - // Emit event with size change so the calling app knows about it too - LLMediaEvent event( this ); - mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// static -Boolean LLMediaImplQuickTime::mcActionFilterCallBack( MovieController mc, short action, void *params, long ref ) -{ - Boolean result = false; - - LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref; - - switch( action ) - { - // handle window resizing - case mcActionControllerSizeChanged: - self->sizeChanged(); - break; - - // Block any movie controller actions that open URLs. - case mcActionLinkToURL: - case mcActionGetNextURL: - case mcActionLinkToURLExtended: - // Prevent the movie controller from handling the message - result = true; - break; - - default: - break; - }; - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -// private -bool LLMediaImplQuickTime::unload() -{ - if ( mMovieHandle ) - { - StopMovie( mMovieHandle ); - if ( mMovieController ) - { - MCMovieChanged( mMovieController, mMovieHandle ); - }; - }; - - if ( mMovieController ) - { - MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this ); - DisposeMovieController( mMovieController ); - mMovieController = NULL; - }; - - if ( mMovieHandle ) - { - SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this ); - DisposeMovie ( mMovieHandle ); - mMovieHandle = NULL; - }; - - if ( mGWorldHandle ) - { - DisposeGWorld( mGWorldHandle ); - mGWorldHandle = NULL; - }; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// static -OSErr LLMediaImplQuickTime::movieDrawingCompleteCallback( Movie call_back_movie, long ref ) -{ - LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref; - - // IMPORTANT: typically, a consumer who is observing this event will set a flag - // when this event is fired then render later. Be aware that the media stream - // can change during this period - dimensions, depth, format etc. - LLMediaEvent event( self ); - self->mEventEmitter.update( &LLMediaObserver::onMediaContentsChange, event ); - - return noErr; -} - -//////////////////////////////////////////////////////////////////////////////// -// static -void LLMediaImplQuickTime::moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref ) -{ - LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref; - - LLMediaEvent event( self ); - self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event ); -} - -/////////////////////////////////////////////////////////////////////////////// -// used for stop / loop -void LLMediaImplQuickTime::rewind() -{ - GoToBeginningOfMovie ( mMovieHandle ); - - MCMovieChanged( mMovieController, mMovieHandle ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaImplQuickTime::processState() -{ - // start stream - if ( nextCommand() == LLMediaBase::COMMAND_START ) - { - // valid when we are in these states - if ( getStatus() == LLMediaBase::STATUS_NAVIGATING|| getStatus() == LLMediaBase::STATUS_STOPPED || getStatus() == LLMediaBase::STATUS_PAUSED ) - { - // it appears that the movie must be in a loaded state before we do this command - if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) - { - MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate( mMovieHandle ) ); - - MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); - - setStatus( LLMediaBase::STATUS_STARTED ); - - clearCommand(); - } - } - } - else - if ( nextCommand() == LLMediaBase::COMMAND_STOP ) - { - // valid when we are in these states - if ( getStatus() == LLMediaBase::STATUS_NAVIGATING || getStatus() == LLMediaBase::STATUS_STARTED || getStatus() == LLMediaBase::STATUS_PAUSED ) - { - // it appears that the movie must be in a loaded state before we do this command - if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) - { - // stop playing - Fixed rate = X2Fix( 0.0 ); - MCDoAction( mMovieController, mcActionPlay, (void*)rate ); - - // go back to start - rewind(); - - setStatus( LLMediaBase::STATUS_STOPPED ); - clearCommand(); - }; - }; - } - else - if ( nextCommand() == LLMediaBase::COMMAND_PAUSE ) - { - // valid when we are in these states - if ( getStatus() == LLMediaBase::STATUS_NAVIGATING || getStatus() == LLMediaBase::STATUS_STARTED || getStatus() == LLMediaBase::STATUS_STOPPED ) - { - // it appears that the movie must be in a loaded state before we do this command - if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) - { - // stop playing - Fixed rate = X2Fix( 0.0 ); - MCDoAction( mMovieController, mcActionPlay, (void*)rate ); - - setStatus( LLMediaBase::STATUS_PAUSED ); - clearCommand(); - }; - }; - }; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplQuickTime::setMovieBoxEnhanced( Rect* rect ) -{ - // get movie rect - GetMovieNaturalBoundsRect( mMovieHandle, rect ); - - int natural_width = ( rect->right - rect->left ); - int natural_height = ( rect->bottom - rect->top ); - - int width = natural_width; - int height = natural_height; - - // if the user has requested a specific size, use it: - if ((mMediaRequestedWidth != 0) && (mMediaRequestedHeight != 0)) - { - width = mMediaRequestedWidth; - height = mMediaRequestedHeight; - } - - // if the user has requested, resize media to exactly fit texture - if (mAutoScaled) - { - width = LLMediaManager::textureWidthFromMediaWidth( width ); - height = LLMediaManager::textureHeightFromMediaHeight( height ); - } - - // make sure it falls in valid range - if ( width < mMinWidth ) - width = mMinWidth; - - if ( width > mMaxWidth ) - width = mMaxWidth; - - if ( height < mMinHeight ) - height = mMinHeight; - - if ( height > mMaxHeight ) - height = mMaxHeight; - - - // scale movie to fit rect and invert vertically to match opengl image format - MatrixRecord transform; - SetIdentityMatrix( &transform ); // transforms are additive so start from identify matrix - double scaleX = (double) width / natural_width; - double scaleY = -1.0 * (double) height / natural_height; - double centerX = width / 2.0; - double centerY = height / 2.0; - ScaleMatrix( &transform, X2Fix ( scaleX ), X2Fix ( scaleY ), X2Fix ( centerX ), X2Fix ( centerY ) ); - SetMovieMatrix( mMovieHandle, &transform ); - - // return the new rect - rect->right = width; - rect->bottom = height; - rect->left = 0; - rect->top = 0; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplQuickTime::updateMedia() -{ - if ( ! mMovieHandle ) - return false; - - if ( ! mMovieController ) - return false; - - if ( ! mGWorldHandle ) - return false; - - // service QuickTime - MoviesTask( mMovieHandle, 0 ); - MCIdle( mMovieController ); - - // update state machine (deals with transport controls for example) - processState(); - - // special code for looping - need to rewind at the end of the movie - - if ( isLooping() ) - { - // QT call to see if we are at the end - can't do with controller - if ( IsMovieDone( mMovieHandle ) ) - { - // go back to start - rewind(); - - // kick off new play - MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate( mMovieHandle ) ); - - // set the volume - MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); - } - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -unsigned char* LLMediaImplQuickTime::getMediaData() -{ - unsigned char* ptr = NULL; - - if ( mGWorldHandle ) - { - PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle ); - - ptr = ( unsigned char* )GetPixBaseAddr( pix_map_handle ); - }; - - return ptr; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -int LLMediaImplQuickTime::getMediaDataWidth() const -{ - if ( mGWorldHandle ) - { - int depth = getMediaDepth(); - - if (depth < 1) - depth = 1; - - // ALWAYS use the row bytes from the PixMap if we have a GWorld because - // sometimes it's not the same as mMediaDepth * mMediaWidth ! - PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle ); - return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth; - } - else - { - return LLMediaImplCommon::getMediaDataWidth(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -int LLMediaImplQuickTime::getTextureFormatPrimary() const -{ -#if defined(__APPLE__) || defined(MACOSX) - return LL_MEDIA_BGRA; -#else - return LL_MEDIA_RGB; -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -int LLMediaImplQuickTime::getTextureFormatType() const -{ -#if defined(__APPLE__) || defined(MACOSX) - #ifdef __BIG_ENDIAN__ - return LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV; - #else - return LL_MEDIA_UNSIGNED_INT_8_8_8_8; - #endif -#else - return LL_MEDIA_UNSIGNED_BYTE; -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplQuickTime::seek( double time ) -{ - if ( mMovieController ) - { - TimeRecord when; - when.scale = GetMovieTimeScale( mMovieHandle ); - when.base = 0; - - // 'time' is in (floating point) seconds. The timebase time will be in 'units', where - // there are 'scale' units per second. - SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) ); - - when.value.hi = ( SInt32 )( raw_time >> 32 ); - when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) ); - - MCDoAction( mMovieController, mcActionGoToTime, &when ); - - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -bool LLMediaImplQuickTime::setVolume( float volume ) -{ - mCurVolume = (short)(volume * ( double ) 0x100 ); - - if ( mMovieController ) - { - MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); - - return true; - } - - return false; -} - -#endif // _3DNOW_InstructionExtensions/ LL_QUICKTIME_ENABLED - diff --git a/linden/indra/llmedia/llmediaimplquicktime.h b/linden/indra/llmedia/llmediaimplquicktime.h deleted file mode 100644 index d4e1db8af..000000000 --- a/linden/indra/llmedia/llmediaimplquicktime.h +++ /dev/null @@ -1,112 +0,0 @@ -/** - * @file llmediaimplquicktime.h - * @brief QuickTime media impl concrete class - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLMEDIAIMPLQUICKTIME_H -#define LLMEDIAIMPLQUICKTIME_H - -#include "llmediaimplcommon.h" -#include "llmediaimplfactory.h" - -#if LL_QUICKTIME_ENABLED - -#include - -// QuickTime includes -#if defined(__APPLE__) - #include -#elif defined(WIN32) - #include "MacTypes.h" - #include "QTML.h" - #include "Movies.h" - #include "QDoffscreen.h" - #include "FixMath.h" -#endif - -class LLMediaManagerData; - -class LLMediaImplQuickTime : - public LLMediaImplCommon -{ - public: - LLMediaImplQuickTime(); - virtual ~LLMediaImplQuickTime(); - - static bool startup( LLMediaManagerData* init_data ); - static bool closedown(); - - /* virtual */ std::string getVersion(); - /* virtual */ bool navigateTo( const std::string url ); - /* virtual */ bool updateMedia(); - /* virtual */ unsigned char* getMediaData(); - /* virtual */ int getMediaDataWidth() const; - /* virtual */ int getTextureFormatPrimary() const; - /* virtual */ int getTextureFormatType() const; - /* virtual */ bool seek( double time ); - /* virtual */ bool setVolume( float volume ); - - bool sizeChanged(); - - private: - static OSErr movieDrawingCompleteCallback( Movie call_back_movie, long ref ); - static Boolean mcActionFilterCallBack( MovieController mc, short action, void *params, long ref ); - static void moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *refcon ); - - bool load( const std::string url ); - bool unload(); - void rewind(); - bool processState(); - bool setMovieBoxEnhanced( Rect* rect ); - - Movie mMovieHandle; - GWorldPtr mGWorldHandle; - ComponentInstance mMovieController; - const int mMinWidth; - const int mMaxWidth; - const int mMinHeight; - const int mMaxHeight; - int mCurVolume; -}; - -// The maker class -class LLMediaImplQuickTimeMaker : public LLMediaImplMaker -{ - public: - LLMediaImplQuickTimeMaker(); - LLMediaImplQuickTime* create() - { - return new LLMediaImplQuickTime(); - } -}; - -#endif // LL_QUICKTIME_ENABLED - -#endif // LLMEDIAIMPLQUICKTIME_H diff --git a/linden/indra/llmedia/llmediamanager.cpp b/linden/indra/llmedia/llmediamanager.cpp deleted file mode 100644 index 48da8082d..000000000 --- a/linden/indra/llmedia/llmediamanager.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/** - * @file llmediamanager.cpp - * @brief Manages instances of media impls - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llmediamanager.h" - -#if LL_WINDOWS - // GStreamer 0.10.22 - gstutils.h - conversion from 'guint64' to 'guint8'. - // This was an intentional change to make GStreamer more threadsafe, and - // is okay. Delete this bit if GStreamer ever gets more VS-friendly -- McCabe - #pragma warning(disable : 4244) -#endif -#include "llmediaimplgstreamer.h" -#if LL_WINDOWS - #pragma warning(default : 4244) -#endif - -#include "llmediaimplfactory.h" - -#include "llmediaimplexample1.h" -#include "llmediaimplexample2.h" -#include "llmediaimplquicktime.h" - -#if LL_LLMOZLIB_ENABLED -# include "llmediaimplllmozlib.h" -#endif - -#include "llerror.h" -LLMediaManager* LLMediaManager::sInstance = 0; - - -//////////////////////////////////////////////////////////////////////////////// -// (private) -LLMediaManager::LLMediaManager() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -LLMediaManager::~LLMediaManager() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// Early initialization for web browser for the viewer, so we can show -// the login screen and defer initialization of QuickTime, etc. JC -// (static) -void LLMediaManager::initBrowser( LLMediaManagerData* init_data ) -{ - if ( ! sInstance ) - sInstance = new LLMediaManager(); - -#if LL_LLMOZLIB_ENABLED - LLMediaImplLLMozLib::startup( init_data ); -#endif // LL_LLMOZLIB_ENABLED -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) -void LLMediaManager::initClass( LLMediaManagerData* init_data ) -{ - if ( ! sInstance ) - sInstance = new LLMediaManager(); - - LL_DEBUGS("MediaManager") << "LLMediaManager::initClass" << LL_ENDL; - // Initialize impl classes here - this breaks the encapsulation model - // but some of the initialization takes a long time and we only want to - // do it once at app startup before any of the impls have been created - // Each impl provides a static startup method that does any initialization - // which takes a significant amount of time. - LLMediaImplExample1::startup( init_data ); - LLMediaImplExample2::startup( init_data ); - -#if LL_QUICKTIME_ENABLED - LL_DEBUGS("MediaManager") << "LLMediaManager::initClass: starting quicktime." << LL_ENDL; - LLMediaImplQuickTime::startup( init_data ); -#endif // LL_QUICKTIME_ENABLED - -///#if LL_GSTREAMER_ENABLED - LL_DEBUGS("MediaManager") << "LLMediaManager::initClass: starting gstreamer" << LL_ENDL; - LLMediaImplGStreamer::startup( init_data ); -///#endif // LL_GSTREAMER_ENABLED -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) -void LLMediaManager::updateClass() -{ - if (!sInstance) return; - - media_impl_container_t::iterator it - = sInstance->mMediaImplContainer.begin(); - media_impl_container_t::iterator end - = sInstance->mMediaImplContainer.end(); - for ( ; it != end; ++it ) - { - LLMediaBase* impl = *it; - impl->updateMedia(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) -void LLMediaManager::cleanupClass() -{ - // Uninitialize impl classes here - this breaks the encapsulation model - // but some of the uninitialization takes a long time and we only want to - // do it once at app startup before any of the impls have been created. - // Each impl provides a static closedown method that does any uninitialization - // which takes a significant amount of time. - LLMediaImplExample1::closedown(); - LLMediaImplExample2::closedown(); - -#if LL_LLMOZLIB_ENABLED - LLMediaImplLLMozLib::closedown(); -#endif // LL_LLMOZLIB_ENABLED - -#if LL_QUICKTIME_ENABLED - LLMediaImplQuickTime::closedown(); -#endif // LL_QUICKTIME_ENABLED - -///#if LL_GSTREAMER_ENABLED - LLMediaImplGStreamer::closedown(); -///#endif // LL_QUICKTIME_ENABLED - - if ( sInstance ) - delete sInstance; - - sInstance = 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) -LLMediaManager* LLMediaManager::getInstance() -{ - return sInstance; -} - -//////////////////////////////////////////////////////////////////////////////// -// (static) -void LLMediaManager::setBrowserUserAgent(std::string user_agent) -{ -#if LL_LLMOZLIB_ENABLED - // *HACK: Breaks encapsulation model, as initClass does above. JC - LLMediaImplLLMozLib::setBrowserUserAgent(user_agent); -#endif // LL_LLMOZLIB_ENABLED -} - -//////////////////////////////////////////////////////////////////////////////// -// -LLMediaBase* LLMediaManager::createSourceFromMimeType( std::string scheme, std::string mime_type ) -{ - - LLMediaImplMakerBase* impl_maker = LLMediaImplFactory::getInstance()->getImplMaker( scheme, mime_type ); - - // If an impl maker is return it means this media type is supported - if ( impl_maker ) - { - LLMediaBase* media_impl = impl_maker->create(); - if( media_impl ) - { - media_impl->setImplMaker( impl_maker ); - std::pair< media_impl_container_t::iterator, bool > result = - mMediaImplContainer.insert( media_impl ); - - if ( result.second ) - { - media_impl->setMimeType( mime_type ); - - media_impl->init(); - - return media_impl; - }; - }; - }; - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaManager::destroySource( LLMediaBase* media_impl ) -{ - media_impl_container_t::iterator iter = - mMediaImplContainer.find( media_impl ); - - if ( iter != mMediaImplContainer.end() ) - { - if ( *iter ) - { - ( *iter)->reset(); - - delete ( *iter ); - - mMediaImplContainer.erase( iter ); - - return true; - }; - }; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaManager::addMimeTypeImplNameMap( std::string mime_type, std::string impl_name ) -{ - std::pair< mime_type_impl_name_container_t::iterator, bool > result = - mMimeTypeImplNameContainer.insert( std::make_pair( mime_type, impl_name ) ); - - return result.second; -} - -//////////////////////////////////////////////////////////////////////////////// -// -std::string LLMediaManager::getImplNameFromMimeType( std::string mime_type ) -{ - mime_type_impl_name_container_t::iterator iter = - mMimeTypeImplNameContainer.find( mime_type ); - - if ( iter != mMimeTypeImplNameContainer.end() ) - { - return ( *iter ).second; - } - else - { - return std::string( "" ); - }; -} -//////////////////////////////////////////////////////////////////////////////// -// -bool LLMediaManager::supportsMediaType( const std::string& impl_name, const std::string& scheme, const std::string& mime_type ) -{ - LLMediaImplMakerBase* impl_maker = LLMediaImplFactory::getInstance()->getImplMaker( impl_name ); - if( impl_maker ) - { - int idx1 = mime_type.find("/"); - int len = (idx1 == std::string::npos) ? 0 : idx1; - std::string category = mime_type.substr(0,len); - - return impl_maker->supportsScheme(scheme) || - impl_maker->supportsMimeType(mime_type) || - impl_maker->supportsMimeTypeCategory(category); - } - return false; -} - -// static -int LLMediaManager::textureWidthFromMediaWidth( int media_width ) -{ - int texture_width = 1; - while ( texture_width < media_width ) - { - texture_width <<= 1; - }; - return texture_width; -} - -// static -int LLMediaManager::textureHeightFromMediaHeight( int media_height ) -{ - int texture_height = 1; - while ( texture_height < media_height ) - { - texture_height <<= 1; - }; - return texture_height; -} diff --git a/linden/indra/llmedia/llmediamanager.h b/linden/indra/llmedia/llmediamanager.h deleted file mode 100644 index dc832d5db..000000000 --- a/linden/indra/llmedia/llmediamanager.h +++ /dev/null @@ -1,127 +0,0 @@ -/** - * @file llmediamanager.h - * @brief Manages instances of media impls - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLMEDIAMANAGER_H -#define LLMEDIAMANAGER_H - -#include -#include - -#include "llmediaimplcommon.h" - -//////////////////////////////////////////////////////////////////////////////// -// -class LLMediaManagerData -{ - public: - LLMediaManagerData() : - mBrowserParentWindow( 0 ), - mBrowserProfileDir( "" ), - mBrowserProfileName ( "" ) - { }; - - void setBrowserApplicationDir( const std::string& browser_application_dir ) { mBrowserApplicationDir = browser_application_dir; }; - std::string& getBrowserApplicationDir() { return mBrowserApplicationDir; }; - - void setBrowserComponentDir( const std::string& browser_component_dir ) { mBrowserComponentDir = browser_component_dir; }; - std::string& getBrowserComponentDir() { return mBrowserComponentDir; }; - - void setBrowserParentWindow( void* browser_parent_window ) { mBrowserParentWindow = browser_parent_window; }; - void* getBrowserParentWindow() { return mBrowserParentWindow; }; - - void setBrowserProfileDir( const std::string& browser_profile_dir ) { mBrowserProfileDir = browser_profile_dir; }; - std::string& getBrowserProfileDir() { return mBrowserProfileDir; }; - - void setBrowserProfileName( const std::string& browser_profile_name ) { mBrowserProfileName = browser_profile_name; }; - std::string& getBrowserProfileName() { return mBrowserProfileName; }; - - private: - void* mBrowserParentWindow; - std::string mBrowserProfileDir; - std::string mBrowserProfileName; - std::string mBrowserApplicationDir; - std::string mBrowserComponentDir; -}; - -//////////////////////////////////////////////////////////////////////////////// -// -class LLMediaManager -{ - public: - virtual ~LLMediaManager(); - - // Special case early init for just web browser component - // so we can show login screen. See .cpp file for details. JC - static void initBrowser( LLMediaManagerData* init_data ); - - static void initClass( LLMediaManagerData* init_data ); - static void cleanupClass(); - static LLMediaManager* getInstance(); - - // We append the skin name to the browser user agent string, so - // we need to change it while the app is running, not just at - // init time. - // Must be called after initClass() above. - // *HACK: Breaks encapsulation model. JC - static void setBrowserUserAgent(std::string user_agent); - - // Calls update on all media sources - static void updateClass(); - - // Given an URL and mime_type, construct/destroy a playback engine for - // it (a "media impl"). - LLMediaBase* createSourceFromMimeType( std::string scheme, std::string mime_type ); - bool destroySource( LLMediaBase* media_impl ); - - // mime type to impl mapping functions - bool addMimeTypeImplNameMap( std::string mime_type, std::string impl_name ); - std::string getImplNameFromMimeType( std::string mime_type ); - - // Name accessor for querying type support - bool supportsMediaType( const std::string& impl_name, const std::string& scheme, const std::string& mime_type ); - - // convenience functions for getting suggested texture sizes to hold various size media - static int textureWidthFromMediaWidth( int media_width ); - static int textureHeightFromMediaHeight( int media_height ); - - private: - LLMediaManager(); - static LLMediaManager* sInstance; - - typedef std::set< LLMediaBase* > media_impl_container_t; - media_impl_container_t mMediaImplContainer; - - typedef std::map< std::string, std::string > mime_type_impl_name_container_t; - mime_type_impl_name_container_t mMimeTypeImplNameContainer; -}; - -#endif // LLMEDIAMANAGER_H diff --git a/linden/indra/llmedia/llmediaobserver.h b/linden/indra/llmedia/llmediaobserver.h deleted file mode 100644 index ab8d7552f..000000000 --- a/linden/indra/llmedia/llmediaobserver.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @file llmediaobserver.h - * @brief Derrive from this class and override methods to observe events from emitter class - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLMEDIAEOBSERVER_H -#define LLMEDIAEOBSERVER_H - -class LLMediaBase; - -class LLMediaEvent -{ - public: - LLMediaEvent( LLMediaBase* subject ) : - mSubject( subject ), mIntValue(-1) - { - }; - - LLMediaEvent( LLMediaBase* subject, std::string in ) : - mSubject( subject ), mIntValue(-1), mStringValue(in) - { - }; - - LLMediaEvent( LLMediaBase* subject, std::string string_in, std::string string_ex_in ) : - mSubject( subject ), mIntValue(-1), mStringValue(string_in), mStringValueEx(string_ex_in) - { - }; - - LLMediaEvent( LLMediaBase* subject, std::string string_in, int int_in ) : - mSubject( subject ), mIntValue(int_in), mStringValue(string_in) - { - }; - - LLMediaEvent( LLMediaBase* subject, int in ) : - mSubject( subject ), mIntValue(in) - { - }; - - virtual ~LLMediaEvent() { } - - LLMediaBase* getSubject() const - { - return mSubject; - }; - - int getIntValue() const - { - return mIntValue; - } - - std::string getStringValue() const - { - return mStringValue; - } - - std::string getStringValueEx() const - { - return mStringValueEx; - } - - private: - LLMediaBase* mSubject; - int mIntValue; - std::string mStringValue; - std::string mStringValueEx; -}; - -class LLMediaObserver -{ - public: - virtual ~LLMediaObserver() {} - - typedef LLMediaEvent EventType; - virtual void onMediaPreroll( const EventType& event_in ) { } - virtual void onMediaLoaded( const EventType& event_in ) { } - virtual void onMediaSizeChange( const EventType& event_in ) { } - virtual void onMediaContentsChange( const EventType& event_in ) { } - virtual void onMediaStatusTextChange( const EventType& event_in ) { } - virtual void onMediaTitleChange( const EventType &event_in ) { } - virtual void onNavigateBegin( const EventType& event_in ) { } - virtual void onNavigateComplete( const EventType& event_in ) { } - virtual void onUpdateProgress( const EventType& event_in ) { } - virtual void onStatusTextChange( const EventType& event_in ) { } - virtual void onLocationChange( const EventType& event_in ) { } - virtual void onClickLinkHref( const EventType& event_in ) { } - virtual void onClickLinkNoFollow( const EventType& event_in ) { } -}; - -#endif // LLMEDIAEOBSERVER_H diff --git a/linden/indra/llmessage/CMakeLists.txt b/linden/indra/llmessage/CMakeLists.txt index a48458074..a5e424925 100644 --- a/linden/indra/llmessage/CMakeLists.txt +++ b/linden/indra/llmessage/CMakeLists.txt @@ -48,6 +48,7 @@ set(llmessage_SOURCE_FILES llmail.cpp llmessagebuilder.cpp llmessageconfig.cpp + llmessagelog.cpp llmessagereader.cpp llmessagetemplate.cpp llmessagetemplateparser.cpp @@ -138,6 +139,7 @@ set(llmessage_HEADER_FILES llmail.h llmessagebuilder.h llmessageconfig.h + llmessagelog.h llmessagereader.h llmessagetemplate.h llmessagetemplateparser.h @@ -216,7 +218,7 @@ IF (NOT LINUX AND VIEWER) # These can not be found when we try to run the tests, so we had to disable them, for the viewer build. # TODO: Can someone with viewer knowledge figure out how to make these find the correct so. #ADD_BUILD_TEST(llhttpclientadapter llmessage) - ADD_BUILD_TEST(lltrustedmessageservice llmessage) - ADD_BUILD_TEST(lltemplatemessagedispatcher llmessage) + #ADD_BUILD_TEST(lltrustedmessageservice llmessage) + #ADD_BUILD_TEST(lltemplatemessagedispatcher llmessage) ENDIF (NOT LINUX AND VIEWER) diff --git a/linden/indra/llmessage/llares.cpp b/linden/indra/llmessage/llares.cpp index fe37fe814..5a6794e03 100644 --- a/linden/indra/llmessage/llares.cpp +++ b/linden/indra/llmessage/llares.cpp @@ -43,6 +43,7 @@ #include "llapr.h" #include "llares.h" +#include "llscopedvolatileaprpool.h" #if defined(LL_WINDOWS) # define ns_c_in 1 @@ -463,11 +464,6 @@ void LLAres::search(const std::string &query, LLResType type, bool LLAres::process(U64 timeout) { - if (!gAPRPoolp) - { - ll_init_apr(); - } - int socks[ARES_GETSOCK_MAXNUM]; apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM]; apr_int32_t nsds = 0; @@ -481,10 +477,7 @@ bool LLAres::process(U64 timeout) return nsds > 0; } - apr_status_t status; - LLAPRPool pool; - status = pool.getStatus() ; - ll_apr_assert_status(status); + LLScopedVolatileAPRPool scoped_pool; for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++) { @@ -501,7 +494,7 @@ bool LLAres::process(U64 timeout) apr_socket_t *aprSock = NULL; - status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool.getAPRPool()); + apr_status_t status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], scoped_pool); if (status != APR_SUCCESS) { ll_apr_warn_status(status); @@ -510,7 +503,7 @@ bool LLAres::process(U64 timeout) aprFds[nactive].desc.s = aprSock; aprFds[nactive].desc_type = APR_POLL_SOCKET; - aprFds[nactive].p = pool.getAPRPool(); + aprFds[nactive].p = scoped_pool; aprFds[nactive].rtnevents = 0; aprFds[nactive].client_data = &socks[i]; @@ -519,7 +512,7 @@ bool LLAres::process(U64 timeout) if (nactive > 0) { - status = apr_poll(aprFds, nactive, &nsds, timeout); + apr_status_t status = apr_poll(aprFds, nactive, &nsds, timeout); if (status != APR_SUCCESS && status != APR_TIMEUP) { diff --git a/linden/indra/llmessage/llassetstorage.cpp b/linden/indra/llmessage/llassetstorage.cpp index 16a96b75b..0ab108120 100644 --- a/linden/indra/llmessage/llassetstorage.cpp +++ b/linden/indra/llmessage/llassetstorage.cpp @@ -1028,12 +1028,12 @@ LLSD LLAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt, { const request_list_t* requests = getRequestList(rt); LLSD sd; - sd["requests"] = getPendingDetails(requests, asset_type, detail_prefix); + sd["requests"] = getPendingDetailsImpl(requests, asset_type, detail_prefix); return sd; } // virtual -LLSD LLAssetStorage::getPendingDetails(const LLAssetStorage::request_list_t* requests, +LLSD LLAssetStorage::getPendingDetailsImpl(const LLAssetStorage::request_list_t* requests, LLAssetType::EType asset_type, const std::string& detail_prefix) const { @@ -1116,11 +1116,11 @@ LLSD LLAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt, const LLUUID& asset_id) const { const request_list_t* requests = getRequestList(rt); - return getPendingRequest(requests, asset_type, asset_id); + return getPendingRequestImpl(requests, asset_type, asset_id); } // virtual -LLSD LLAssetStorage::getPendingRequest(const LLAssetStorage::request_list_t* requests, +LLSD LLAssetStorage::getPendingRequestImpl(const LLAssetStorage::request_list_t* requests, LLAssetType::EType asset_type, const LLUUID& asset_id) const { @@ -1139,7 +1139,7 @@ bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt, const LLUUID& asset_id) { request_list_t* requests = getRequestList(rt); - if (deletePendingRequest(requests, asset_type, asset_id)) + if (deletePendingRequestImpl(requests, asset_type, asset_id)) { llinfos << "Asset " << getRequestName(rt) << " request for " << asset_id << "." << LLAssetType::lookup(asset_type) @@ -1150,7 +1150,7 @@ bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt, } // virtual -bool LLAssetStorage::deletePendingRequest(LLAssetStorage::request_list_t* requests, +bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* requests, LLAssetType::EType asset_type, const LLUUID& asset_id) { diff --git a/linden/indra/llmessage/llassetstorage.h b/linden/indra/llmessage/llassetstorage.h index c094ef487..83cfdf611 100644 --- a/linden/indra/llmessage/llassetstorage.h +++ b/linden/indra/llmessage/llassetstorage.h @@ -315,15 +315,15 @@ class LLAssetStorage : public LLTempAssetStorage void markAssetToxic( const LLUUID& uuid ); protected: - virtual LLSD getPendingDetails(const request_list_t* requests, + virtual LLSD getPendingDetailsImpl(const request_list_t* requests, LLAssetType::EType asset_type, const std::string& detail_prefix) const; - virtual LLSD getPendingRequest(const request_list_t* requests, + virtual LLSD getPendingRequestImpl(const request_list_t* requests, LLAssetType::EType asset_type, const LLUUID& asset_id) const; - virtual bool deletePendingRequest(request_list_t* requests, + virtual bool deletePendingRequestImpl(request_list_t* requests, LLAssetType::EType asset_type, const LLUUID& asset_id); diff --git a/linden/indra/llmessage/llcircuit.cpp b/linden/indra/llmessage/llcircuit.cpp index 725425cc2..0ff5093ca 100644 --- a/linden/indra/llmessage/llcircuit.cpp +++ b/linden/indra/llmessage/llcircuit.cpp @@ -1231,6 +1231,17 @@ void LLCircuit::getCircuitRange( first = mCircuitData.upper_bound(key); } +// +std::vector LLCircuit::getCircuitDataList() +{ + std::vector list; + circuit_data_map::iterator end = mCircuitData.end(); + for(circuit_data_map::iterator iter = mCircuitData.begin(); iter != end; ++iter) + list.push_back((*iter).second); + return list; +} +// + TPACKETID LLCircuitData::nextPacketOutID() { mPacketsOut++; diff --git a/linden/indra/llmessage/llcircuit.h b/linden/indra/llmessage/llcircuit.h index e373cb116..379453e19 100644 --- a/linden/indra/llmessage/llcircuit.h +++ b/linden/indra/llmessage/llcircuit.h @@ -336,6 +336,9 @@ class LLCircuit // HACK - this should become protected eventually, but stupid !@$@# message system/circuit classes are jumbling things up. circuit_data_map mUnackedCircuitMap; // Map of circuits with unacked data circuit_data_map mSendAckMap; // Map of circuits which need to send acks + + std::vector getCircuitDataList(); + protected: circuit_data_map mCircuitData; diff --git a/linden/indra/llmessage/llcurl.cpp b/linden/indra/llmessage/llcurl.cpp index 12321feba..9ecfee417 100644 --- a/linden/indra/llmessage/llcurl.cpp +++ b/linden/indra/llmessage/llcurl.cpp @@ -120,7 +120,7 @@ LLCurl::Responder::~Responder() } // virtual -void LLCurl::Responder::error( +void LLCurl::Responder::errorWithContent( U32 status, const std::string& reason, const LLSD&) @@ -161,7 +161,7 @@ void LLCurl::Responder::completed(U32 status, const std::string& reason, const L } else { - error(status, reason, content); + errorWithContent(status, reason, content); } } @@ -1020,7 +1020,7 @@ void LLCurl::initClass() S32 mutex_count = CRYPTO_num_locks(); for (S32 i=0; iresult(get()); + response->result(simpleGet()); } catch (NotImplemented) { @@ -134,7 +134,7 @@ void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, cons { try { - response->result(put(input)); + response->result(simplePut(input)); } catch (NotImplemented) { @@ -147,7 +147,7 @@ void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, con { try { - response->result(post(input)); + response->result(simplePost(input)); } catch (NotImplemented) { @@ -160,7 +160,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons { try { - response->result(del(context)); + response->result(simpleDel(context)); } catch (NotImplemented) { @@ -170,7 +170,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons } // virtual -LLSD LLHTTPNode::del(const LLSD&) const +LLSD LLHTTPNode::simpleDel(const LLSD&) const { throw NotImplemented(); } @@ -388,7 +388,7 @@ LLHTTPNode::Response::~Response() { } -void LLHTTPNode::Response::status(S32 code) +void LLHTTPNode::Response::statusUnknownError(S32 code) { status(code, "Unknown Error"); } diff --git a/linden/indra/llmessage/llhttpnode.h b/linden/indra/llmessage/llhttpnode.h index 17ffd66e8..87f0c480f 100644 --- a/linden/indra/llmessage/llhttpnode.h +++ b/linden/indra/llmessage/llhttpnode.h @@ -83,10 +83,10 @@ class LLHTTPNode //@{ public: - virtual LLSD get() const; - virtual LLSD put(const LLSD& input) const; - virtual LLSD post(const LLSD& input) const; - virtual LLSD del(const LLSD& context) const; + virtual LLSD simpleGet() const; + virtual LLSD simplePut(const LLSD& input) const; + virtual LLSD simplePost(const LLSD& input) const; + virtual LLSD simpleDel(const LLSD& context) const; /** * @brief Abstract Base Class declaring Response interface. @@ -116,7 +116,7 @@ class LLHTTPNode /** * @brief Return no body, just status code and 'UNKNOWN ERROR'. */ - virtual void status(S32 code); + virtual void statusUnknownError(S32 code); virtual void notFound(const std::string& message); virtual void notFound(); diff --git a/linden/indra/llmessage/lliohttpserver.cpp b/linden/indra/llmessage/lliohttpserver.cpp index 83dfa94f0..8ad052b91 100644 --- a/linden/indra/llmessage/lliohttpserver.cpp +++ b/linden/indra/llmessage/lliohttpserver.cpp @@ -948,13 +948,9 @@ class LLHTTPResponseFactory : public LLChainIOFactory // static -LLHTTPNode& LLIOHTTPServer::create( - apr_pool_t* pool, LLPumpIO& pump, U16 port) +LLHTTPNode& LLIOHTTPServer::create(LLPumpIO& pump, U16 port) { - LLSocket::ptr_t socket = LLSocket::create( - pool, - LLSocket::STREAM_TCP, - port); + LLSocket::ptr_t socket = LLSocket::create(LLSocket::STREAM_TCP, port); if(!socket) { llerrs << "Unable to initialize socket" << llendl; @@ -963,7 +959,7 @@ LLHTTPNode& LLIOHTTPServer::create( LLHTTPResponseFactory* factory = new LLHTTPResponseFactory; boost::shared_ptr factory_ptr(factory); - LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr); + LLIOServerSocket* server = new LLIOServerSocket(socket, factory_ptr); LLPumpIO::chain_t chain; chain.push_back(LLIOPipe::ptr_t(server)); diff --git a/linden/indra/llmessage/lliohttpserver.h b/linden/indra/llmessage/lliohttpserver.h index d1c9bdde8..d2a8e2a8f 100644 --- a/linden/indra/llmessage/lliohttpserver.h +++ b/linden/indra/llmessage/lliohttpserver.h @@ -57,7 +57,7 @@ class LLIOHTTPServer public: typedef void (*timing_callback_t)(const char* hashed_name, F32 time, void* data); - static LLHTTPNode& create(apr_pool_t* pool, LLPumpIO& pump, U16 port); + static LLHTTPNode& create(LLPumpIO& pump, U16 port); /**< Creates an HTTP wire server on the pump for the given TCP port. * * Returns the root node of the new server. Add LLHTTPNode instances diff --git a/linden/indra/llmessage/lliosocket.cpp b/linden/indra/llmessage/lliosocket.cpp index 7ec577c7b..686c03742 100644 --- a/linden/indra/llmessage/lliosocket.cpp +++ b/linden/indra/llmessage/lliosocket.cpp @@ -41,6 +41,7 @@ #include "llhost.h" #include "llmemtype.h" #include "llpumpio.h" +#include "llthread.h" // // constants @@ -104,51 +105,31 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock) /// // static -LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) +LLSocket::ptr_t LLSocket::create(EType type, U16 port) { LLMemType m1(LLMemType::MTYPE_IO_TCP); - LLSocket::ptr_t rv; - apr_socket_t* socket = NULL; - apr_pool_t* new_pool = NULL; apr_status_t status = APR_EGENERAL; - - // create a pool for the socket - status = apr_pool_create(&new_pool, pool); - if(ll_apr_warn_status(status)) - { - if(new_pool) apr_pool_destroy(new_pool); - return rv; - } + LLSocket::ptr_t rv(new LLSocket); if(STREAM_TCP == type) { - status = apr_socket_create( - &socket, - APR_INET, - SOCK_STREAM, - APR_PROTO_TCP, - new_pool); + status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, rv->mPool()); } else if(DATAGRAM_UDP == type) { - status = apr_socket_create( - &socket, - APR_INET, - SOCK_DGRAM, - APR_PROTO_UDP, - new_pool); + status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, rv->mPool()); } else { - if(new_pool) apr_pool_destroy(new_pool); + rv.reset(); return rv; } if(ll_apr_warn_status(status)) { - if(new_pool) apr_pool_destroy(new_pool); + rv->mSocket = NULL; + rv.reset(); return rv; } - rv = ptr_t(new LLSocket(socket, new_pool)); if(port > 0) { apr_sockaddr_t* sa = NULL; @@ -158,7 +139,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) APR_UNSPEC, port, 0, - new_pool); + rv->mPool()); if(ll_apr_warn_status(status)) { rv.reset(); @@ -166,8 +147,8 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) } // This allows us to reuse the address on quick down/up. This // is unlikely to create problems. - ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1)); - status = apr_socket_bind(socket, sa); + ll_apr_warn_status(apr_socket_opt_set(rv->mSocket, APR_SO_REUSEADDR, 1)); + status = apr_socket_bind(rv->mSocket, sa); if(ll_apr_warn_status(status)) { rv.reset(); @@ -181,7 +162,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) // to keep a queue of incoming connections for ACCEPT. lldebugs << "Setting listen state for socket." << llendl; status = apr_socket_listen( - socket, + rv->mSocket, LL_DEFAULT_LISTEN_BACKLOG); if(ll_apr_warn_status(status)) { @@ -202,21 +183,28 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) } // static -LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool) +LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_socket) { LLMemType m1(LLMemType::MTYPE_IO_TCP); - LLSocket::ptr_t rv; - if(!socket) + if (!listen_socket->getSocket()) + { + status = APR_ENOSOCKET; + return LLSocket::ptr_t(); + } + LLSocket::ptr_t rv(new LLSocket); + lldebugs << "accepting socket" << llendl; + status = apr_socket_accept(&rv->mSocket, listen_socket->getSocket(), rv->mPool()); + if (status != APR_SUCCESS) { + rv->mSocket = NULL; + rv.reset(); return rv; } - rv = ptr_t(new LLSocket(socket, pool)); rv->mPort = PORT_EPHEMERAL; rv->setOptions(); return rv; } - bool LLSocket::blockingConnect(const LLHost& host) { if(!mSocket) return false; @@ -229,7 +217,7 @@ bool LLSocket::blockingConnect(const LLHost& host) APR_UNSPEC, host.getPort(), 0, - mPool))) + mPool()))) { return false; } @@ -240,13 +228,11 @@ bool LLSocket::blockingConnect(const LLHost& host) return true; } -LLSocket::LLSocket(apr_socket_t* socket, apr_pool_t* pool) : - mSocket(socket), - mPool(pool), +LLSocket::LLSocket() : + mSocket(NULL), + mPool(LLThread::tldata().mRootPool), mPort(PORT_INVALID) { - ll_debug_socket("Constructing wholely formed socket", mSocket); - LLMemType m1(LLMemType::MTYPE_IO_TCP); } LLSocket::~LLSocket() @@ -258,10 +244,6 @@ LLSocket::~LLSocket() ll_debug_socket("Destroying socket", mSocket); apr_socket_close(mSocket); } - if(mPool) - { - apr_pool_destroy(mPool); - } } void LLSocket::setOptions() @@ -522,10 +504,8 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl( /// LLIOServerSocket::LLIOServerSocket( - apr_pool_t* pool, LLIOServerSocket::socket_t listener, factory_t factory) : - mPool(pool), mListenSocket(listener), mReactor(factory), mInitialized(false), @@ -585,21 +565,15 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( lldebugs << "accepting socket" << llendl; PUMP_DEBUG; - apr_pool_t* new_pool = NULL; - apr_status_t status = apr_pool_create(&new_pool, mPool); - apr_socket_t* socket = NULL; - status = apr_socket_accept( - &socket, - mListenSocket->getSocket(), - new_pool); - LLSocket::ptr_t llsocket(LLSocket::create(socket, new_pool)); + apr_status_t status; + LLSocket::ptr_t llsocket(LLSocket::create(status, mListenSocket)); //EStatus rv = STATUS_ERROR; - if(llsocket) + if(llsocket && status == APR_SUCCESS) { PUMP_DEBUG; apr_sockaddr_t* remote_addr; - apr_socket_addr_get(&remote_addr, APR_REMOTE, socket); + apr_socket_addr_get(&remote_addr, APR_REMOTE, llsocket->getSocket()); char* remote_host_string; apr_sockaddr_ip_get(&remote_host_string, remote_addr); @@ -614,7 +588,6 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( { chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket))); pump->addChain(chain, mResponseTimeout); - status = STATUS_OK; } else { @@ -623,7 +596,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( } else { - llwarns << "Unable to create linden socket." << llendl; + char buf[256]; + llwarns << "Unable to accept linden socket: " << apr_strerror(status, buf, sizeof(buf)) << llendl; } PUMP_DEBUG; @@ -636,11 +610,10 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( #if 0 LLIODataSocket::LLIODataSocket( U16 suggested_port, - U16 start_discovery_port, - apr_pool_t* pool) : + U16 start_discovery_port) : mSocket(NULL) { - if(!pool || (PORT_INVALID == suggested_port)) return; + if(PORT_INVALID == suggested_port) return; if(ll_apr_warn_status(apr_socket_create(&mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, pool))) return; apr_sockaddr_t* sa = NULL; if(ll_apr_warn_status(apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_UNSPEC, suggested_port, 0, pool))) return; diff --git a/linden/indra/llmessage/lliosocket.h b/linden/indra/llmessage/lliosocket.h index ec09ad8ba..5ad75e909 100644 --- a/linden/indra/llmessage/lliosocket.h +++ b/linden/indra/llmessage/lliosocket.h @@ -44,7 +44,6 @@ */ #include "lliopipe.h" -#include "apr_pools.h" #include "apr_network_io.h" #include "llchainio.h" @@ -94,34 +93,22 @@ class LLSocket * socket. If you intend the socket to be known to external * clients without prior port notification, do not use * PORT_EPHEMERAL. - * @param pool The apr pool to use. A child pool will be created - * and associated with the socket. * @param type The type of socket to create * @param port The port for the socket * @return A valid socket shared pointer if the call worked. */ static ptr_t create( - apr_pool_t* pool, EType type, U16 port = PORT_EPHEMERAL); /** - * @brief Create a LLSocket when you already have an apr socket. + * @brief Create a LLSocket by accepting a connection from a listen socket. * - * This method assumes an ephemeral port. This is typically used - * by calls which spawn a socket such as a call to - * accept() as in the server socket. This call should - * not fail if you have a valid apr socket. - * Because of the nature of how accept() works, you are expected - * to create a new pool for the socket, use that pool for the - * accept, and pass it in here where it will be bound with the - * socket and destroyed at the same time. - * @param socket The apr socket to use - * @param pool The pool used to create the socket. *NOTE: The pool - * passed in will be DESTROYED. + * @param status Output. Status of the accept if a valid listen socket was passed. + * @param listen_socket The listen socket to use. * @return A valid socket shared pointer if the call worked. */ - static ptr_t create(apr_socket_t* socket, apr_pool_t* pool); + static ptr_t create(apr_status_t& status, ptr_t& listen_socket); /** * @brief Perform a blocking connect to a host. Do not use in production. @@ -156,7 +143,7 @@ class LLSocket * @brief Protected constructor since should only make sockets * with one of the two create() calls. */ - LLSocket(apr_socket_t* socket, apr_pool_t* pool); + LLSocket(void); /** * @brief Set default socket options. @@ -173,8 +160,8 @@ class LLSocket // The apr socket. apr_socket_t* mSocket; - // our memory pool - apr_pool_t* mPool; + // Our memory pool. + AIAPRPool mPool; // The port if we know it. U16 mPort; @@ -299,7 +286,7 @@ class LLIOServerSocket : public LLIOPipe public: typedef LLSocket::ptr_t socket_t; typedef boost::shared_ptr factory_t; - LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor); + LLIOServerSocket(socket_t listener, factory_t reactor); virtual ~LLIOServerSocket(); /** @@ -331,7 +318,6 @@ class LLIOServerSocket : public LLIOPipe //@} protected: - apr_pool_t* mPool; socket_t mListenSocket; factory_t mReactor; bool mInitialized; @@ -365,8 +351,7 @@ class LLIODataSocket : public LLIOSocket */ LLIODataSocket( U16 suggested_port, - U16 start_discovery_port, - apr_pool_t* pool); + U16 start_discovery_port); virtual ~LLIODataSocket(); protected: diff --git a/linden/indra/llmessage/llmail.cpp b/linden/indra/llmessage/llmail.cpp index d52ff6c7e..8850e2967 100644 --- a/linden/indra/llmessage/llmail.cpp +++ b/linden/indra/llmessage/llmail.cpp @@ -56,6 +56,7 @@ #include "llstring.h" #include "lluuid.h" #include "net.h" +#include "aiaprpool.h" // // constants @@ -63,7 +64,7 @@ const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096; static bool gMailEnabled = true; -static apr_pool_t* gMailPool; +static AIAPRPool gMailPool; static apr_sockaddr_t* gSockAddr; static apr_socket_t* gMailSocket; @@ -88,7 +89,7 @@ bool connect_smtp() gSockAddr->sa.sin.sin_family, SOCK_STREAM, APR_PROTO_TCP, - gMailPool); + gMailPool()); if(ll_apr_warn_status(status)) return false; status = apr_socket_connect(gMailSocket, gSockAddr); if(ll_apr_warn_status(status)) @@ -145,19 +146,19 @@ BOOL LLMail::send( } // static -void LLMail::init(const std::string& hostname, apr_pool_t* pool) +void LLMail::init(const std::string& hostname) { gMailSocket = NULL; - if(hostname.empty() || !pool) + if (hostname.empty()) { - gMailPool = NULL; gSockAddr = NULL; + gMailPool.destroy(); } else { - gMailPool = pool; + gMailPool.create(); - // collect all the information into a socaddr sturcture. the + // Collect all the information into a sockaddr structure. the // documentation is a bit unclear, but I either have to // specify APR_UNSPEC or not specify any flags. I am not sure // which option is better. @@ -167,7 +168,7 @@ void LLMail::init(const std::string& hostname, apr_pool_t* pool) APR_UNSPEC, 25, APR_IPV4_ADDR_OK, - gMailPool); + gMailPool()); ll_apr_warn_status(status); } } diff --git a/linden/indra/llmessage/llmail.h b/linden/indra/llmessage/llmail.h index 7effb847a..7026d93b3 100644 --- a/linden/indra/llmessage/llmail.h +++ b/linden/indra/llmessage/llmail.h @@ -33,15 +33,13 @@ #ifndef LL_LLMAIL_H #define LL_LLMAIL_H -typedef struct apr_pool_t apr_pool_t; - #include "llsd.h" class LLMail { public: // if hostname is NULL, then the host is resolved as 'mail' - static void init(const std::string& hostname, apr_pool_t* pool); + static void init(const std::string& hostname); // Allow all email transmission to be disabled/enabled. static void enable(bool mail_enabled); diff --git a/linden/indra/llmessage/llmessagelog.cpp b/linden/indra/llmessage/llmessagelog.cpp new file mode 100644 index 000000000..965b8c0de --- /dev/null +++ b/linden/indra/llmessage/llmessagelog.cpp @@ -0,0 +1,54 @@ +// +#include "llmessagelog.h" + +LLMessageLogEntry::LLMessageLogEntry(EType type, LLHost from_host, LLHost to_host, U8* data, S32 data_size) +: mType(type), + mFromHost(from_host), + mToHost(to_host), + mDataSize(data_size) +{ + if(data) + { + mData.resize(data_size); + memcpy(&(mData[0]), data, data_size); + } +} +LLMessageLogEntry::LLMessageLogEntry(EType type, LLHost from_host, LLHost to_host, std::vector data, S32 data_size) +: mType(type), + mFromHost(from_host), + mToHost(to_host), + mDataSize(data_size), + mData(data) +{ +} +LLMessageLogEntry::~LLMessageLogEntry() +{ +} +U32 LLMessageLog::sMaxSize = 4096; // testzone fixme todo boom +std::deque LLMessageLog::sDeque; +void (*(LLMessageLog::sCallback))(LLMessageLogEntry); +void LLMessageLog::setMaxSize(U32 size) +{ + sMaxSize = size; + while(sDeque.size() > sMaxSize) + sDeque.pop_front(); +} +void LLMessageLog::setCallback(void (*callback)(LLMessageLogEntry)) +{ + sCallback = callback; +} +void LLMessageLog::log(LLHost from_host, LLHost to_host, U8* data, S32 data_size) +{ + LLMessageLogEntry entry = LLMessageLogEntry(LLMessageLogEntry::TEMPLATE, from_host, to_host, data, data_size); + if(!entry.mDataSize || !entry.mData.size()) return; + if(sCallback) sCallback(entry); + if(!sMaxSize) return; + sDeque.push_back(entry); + if(sDeque.size() > sMaxSize) + sDeque.pop_front(); +} +std::deque LLMessageLog::getDeque() +{ + return sDeque; +} +// diff --git a/linden/indra/llmessage/llmessagelog.h b/linden/indra/llmessage/llmessagelog.h new file mode 100644 index 000000000..5046d808b --- /dev/null +++ b/linden/indra/llmessage/llmessagelog.h @@ -0,0 +1,41 @@ +// +#ifndef LL_LLMESSAGELOG_H +#define LL_LLMESSAGELOG_H +#include "stdtypes.h" +#include "llhost.h" +#include +#include + +class LLMessageSystem; +class LLMessageLogEntry +{ +public: + enum EType + { + TEMPLATE, + HTTP_REQUEST, + HTTP_RESPONSE + }; + LLMessageLogEntry(EType type, LLHost from_host, LLHost to_host, U8* data, S32 data_size); + LLMessageLogEntry(EType type, LLHost from_host, LLHost to_host, std::vector data, S32 data_size); + ~LLMessageLogEntry(); + EType mType; + LLHost mFromHost; + LLHost mToHost; + S32 mDataSize; + std::vector mData; +}; +class LLMessageLog +{ +public: + static void setMaxSize(U32 size); + static void setCallback(void (*callback)(LLMessageLogEntry)); + static void log(LLHost from_host, LLHost to_host, U8* data, S32 data_size); + static std::deque getDeque(); +private: + static U32 sMaxSize; + static void (*sCallback)(LLMessageLogEntry); + static std::deque sDeque; +}; +#endif +// diff --git a/linden/indra/llmessage/llpacketring.cpp b/linden/indra/llmessage/llpacketring.cpp index 35d5aac77..7dcb606ce 100644 --- a/linden/indra/llmessage/llpacketring.cpp +++ b/linden/indra/llmessage/llpacketring.cpp @@ -40,6 +40,8 @@ #include "timing.h" #include "llrand.h" #include "u64.h" +#include "llmessagelog.h" +#include "message.h" /////////////////////////////////////////////////////////// LLPacketRing::LLPacketRing () : @@ -246,6 +248,9 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap) BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host) { + // + LLMessageLog::log(LLHost(16777343, gMessageSystem->getListenPort()), host, (U8*)send_buffer, buf_size); + // BOOL status = TRUE; if (!mUseOutThrottle) { diff --git a/linden/indra/llmessage/llpumpio.cpp b/linden/indra/llmessage/llpumpio.cpp index 3e3f0b37a..6f10c6b68 100644 --- a/linden/indra/llmessage/llpumpio.cpp +++ b/linden/indra/llmessage/llpumpio.cpp @@ -43,6 +43,8 @@ #include "llmemtype.h" #include "llstl.h" #include "llstat.h" +#include "llthread.h" +#include "llfasttimer.h" // These should not be enabled in production, but they can be // intensely useful during development for finding certain kinds of @@ -168,14 +170,12 @@ struct ll_delete_apr_pollset_fd_client_data /** * LLPumpIO */ -LLPumpIO::LLPumpIO(apr_pool_t* pool) : +LLPumpIO::LLPumpIO(void) : mState(LLPumpIO::NORMAL), mRebuildPollset(false), mPollset(NULL), mPollsetClientID(0), mNextLock(0), - mPool(NULL), - mCurrentPool(NULL), mCurrentPoolReallocCount(0), mChainsMutex(NULL), mCallbackMutex(NULL), @@ -184,21 +184,24 @@ LLPumpIO::LLPumpIO(apr_pool_t* pool) : mCurrentChain = mRunningChains.end(); LLMemType m1(LLMemType::MTYPE_IO_PUMP); - initialize(pool); + initialize(); } LLPumpIO::~LLPumpIO() { LLMemType m1(LLMemType::MTYPE_IO_PUMP); - cleanup(); -} - -bool LLPumpIO::prime(apr_pool_t* pool) -{ - LLMemType m1(LLMemType::MTYPE_IO_PUMP); - cleanup(); - initialize(pool); - return ((pool == NULL) ? false : true); +#if LL_THREADS_APR + if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex); + if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex); +#endif + mChainsMutex = NULL; + mCallbackMutex = NULL; + if(mPollset) + { +// lldebugs << "cleaning up pollset" << llendl; + apr_pollset_destroy(mPollset); + mPollset = NULL; + } } bool LLPumpIO::addChain(const chain_t& chain, F32 timeout) @@ -358,8 +361,7 @@ bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll) { // each fd needs a pool to work with, so if one was // not specified, use this pool. - // *FIX: Should it always be this pool? - value.second.p = mPool; + value.second.p = (*mCurrentChain).mDescriptorsPool->operator()(); } value.second.client_data = new S32(++mPollsetClientID); (*mCurrentChain).mDescriptors.push_back(value); @@ -826,39 +828,15 @@ void LLPumpIO::control(LLPumpIO::EControl op) } } -void LLPumpIO::initialize(apr_pool_t* pool) +void LLPumpIO::initialize(void) { LLMemType m1(LLMemType::MTYPE_IO_PUMP); - if(!pool) return; + mPool.create(); #if LL_THREADS_APR // SJB: Windows defaults to NESTED and OSX defaults to UNNESTED, so use UNNESTED explicitly. - apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, pool); - apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, pool); -#endif - mPool = pool; -} - -void LLPumpIO::cleanup() -{ - LLMemType m1(LLMemType::MTYPE_IO_PUMP); -#if LL_THREADS_APR - if(mChainsMutex) apr_thread_mutex_destroy(mChainsMutex); - if(mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex); + apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, mPool()); + apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool()); #endif - mChainsMutex = NULL; - mCallbackMutex = NULL; - if(mPollset) - { -// lldebugs << "cleaning up pollset" << llendl; - apr_pollset_destroy(mPollset); - mPollset = NULL; - } - if(mCurrentPool) - { - apr_pool_destroy(mCurrentPool); - mCurrentPool = NULL; - } - mPool = NULL; } void LLPumpIO::rebuildPollset() @@ -886,21 +864,19 @@ void LLPumpIO::rebuildPollset() if(mCurrentPool && (0 == (++mCurrentPoolReallocCount % POLLSET_POOL_RECYCLE_COUNT))) { - apr_pool_destroy(mCurrentPool); - mCurrentPool = NULL; + mCurrentPool.destroy(); mCurrentPoolReallocCount = 0; } if(!mCurrentPool) { - apr_status_t status = apr_pool_create(&mCurrentPool, mPool); - (void)ll_apr_warn_status(status); + mCurrentPool.create(mPool); } // add all of the file descriptors run_it = mRunningChains.begin(); LLChainInfo::conditionals_t::iterator fd_it; LLChainInfo::conditionals_t::iterator fd_end; - apr_pollset_create(&mPollset, size, mCurrentPool, 0); + apr_pollset_create(&mPollset, size, mCurrentPool(), 0); for(; run_it != run_end; ++run_it) { fd_it = (*run_it).mDescriptors.begin(); @@ -1158,7 +1134,8 @@ bool LLPumpIO::handleChainError( LLPumpIO::LLChainInfo::LLChainInfo() : mInit(false), mLock(0), - mEOS(false) + mEOS(false), + mDescriptorsPool(new AIAPRPool(LLThread::tldata().mRootPool)) { LLMemType m1(LLMemType::MTYPE_IO_PUMP); mTimer.setTimerExpirySec(DEFAULT_CHAIN_EXPIRY_SECS); diff --git a/linden/indra/llmessage/llpumpio.h b/linden/indra/llmessage/llpumpio.h index fc0bfabaa..2666be04a 100644 --- a/linden/indra/llmessage/llpumpio.h +++ b/linden/indra/llmessage/llpumpio.h @@ -36,11 +36,12 @@ #define LL_LLPUMPIO_H #include +#include #if LL_LINUX // needed for PATH_MAX in APR. #include #endif -#include "apr_pools.h" +#include "aiaprpool.h" #include "llbuffer.h" #include "llframetimer.h" #include "lliopipe.h" @@ -64,9 +65,8 @@ extern const F32 NEVER_CHAIN_EXPIRY_SECS; * pump() on a thread used for IO and call * respond() on a thread that is expected to do higher * level processing. You can call almost any other method from any - * thread - see notes for each method for details. In order for the - * threading abstraction to work, you need to call prime() - * with a valid apr pool. + * thread - see notes for each method for details. + * * A pump instance manages much of the state for the pipe, including * the list of pipes in the chain, the channel for each element in the * chain, the buffer, and if any pipe has marked the stream or process @@ -85,24 +85,13 @@ class LLPumpIO /** * @brief Constructor. */ - LLPumpIO(apr_pool_t* pool); + LLPumpIO(void); /** * @brief Destructor. */ ~LLPumpIO(); - /** - * @brief Prepare this pump for usage. - * - * If you fail to call this method prior to use, the pump will - * try to work, but will not come with any thread locking - * mechanisms. - * @param pool The apr pool to use. - * @return Returns true if the pump is primed. - */ - bool prime(apr_pool_t* pool); - /** * @brief Typedef for having a chain of pipes. */ @@ -374,6 +363,7 @@ class LLPumpIO typedef std::pair pipe_conditional_t; typedef std::vector conditionals_t; conditionals_t mDescriptors; + boost::shared_ptr mDescriptorsPool; }; // All the running chains & info @@ -392,9 +382,9 @@ class LLPumpIO callbacks_t mPendingCallbacks; callbacks_t mCallbacks; - // memory allocator for pollsets & mutexes. - apr_pool_t* mPool; - apr_pool_t* mCurrentPool; + // Memory pool for pollsets & mutexes. + AIAPRPool mPool; + AIAPRPool mCurrentPool; S32 mCurrentPoolReallocCount; #if LL_THREADS_APR @@ -406,8 +396,7 @@ class LLPumpIO #endif protected: - void initialize(apr_pool_t* pool); - void cleanup(); + void initialize(); /** * @brief Given the internal state of the chains, rebuild the pollset diff --git a/linden/indra/llmessage/llregionpresenceverifier.cpp b/linden/indra/llmessage/llregionpresenceverifier.cpp index 24410a7a0..04eba34b6 100644 --- a/linden/indra/llmessage/llregionpresenceverifier.cpp +++ b/linden/indra/llmessage/llregionpresenceverifier.cpp @@ -30,6 +30,7 @@ * $/LicenseInfo$ */ +#include "linden_common.h" #include "llregionpresenceverifier.h" #include "llhttpclientinterface.h" #include diff --git a/linden/indra/llmessage/llsdappservices.cpp b/linden/indra/llmessage/llsdappservices.cpp index dc135c51b..b87c0cd6b 100644 --- a/linden/indra/llmessage/llsdappservices.cpp +++ b/linden/indra/llmessage/llsdappservices.cpp @@ -56,7 +56,7 @@ class LLHTTPConfigService : public LLHTTPNode desc.source(__FILE__, __LINE__); } - virtual LLSD get() const + virtual LLSD simpleGet() const { LLSD result; LLApp* app = LLApp::instance(); @@ -82,7 +82,7 @@ class LLHTTPConfigRuntimeService : public LLHTTPNode desc.source(__FILE__, __LINE__); } - virtual LLSD get() const + virtual LLSD simpleGet() const { return LLApp::instance()->getOptionData( LLApp::PRIORITY_RUNTIME_OVERRIDE); diff --git a/linden/indra/llmessage/llsdhttpserver.cpp b/linden/indra/llmessage/llsdhttpserver.cpp index 00fc170c5..7d06c298a 100644 --- a/linden/indra/llmessage/llsdhttpserver.cpp +++ b/linden/indra/llmessage/llsdhttpserver.cpp @@ -62,7 +62,7 @@ class LLHTTPHelloService : public LLHTTPNode desc.source(__FILE__, __LINE__); } - virtual LLSD get() const + virtual LLSD simpleGet() const { LLSD result = "hello"; return result; @@ -86,7 +86,7 @@ class LLHTTPEchoService : public LLHTTPNode desc.source(__FILE__, __LINE__); } - virtual LLSD post(const LLSD& params) const + virtual LLSD simplePost(const LLSD& params) const { return params; } diff --git a/linden/indra/llmessage/lltemplatemessagereader.cpp b/linden/indra/llmessage/lltemplatemessagereader.cpp index d8904a9ce..9f68fe979 100644 --- a/linden/indra/llmessage/lltemplatemessagereader.cpp +++ b/linden/indra/llmessage/lltemplatemessagereader.cpp @@ -449,7 +449,10 @@ S32 LLTemplateMessageReader::getMessageSize() const // Returns template for the message contained in buffer BOOL LLTemplateMessageReader::decodeTemplate( const U8* buffer, S32 buffer_size, // inputs - LLMessageTemplate** msg_template ) // outputs + // + //LLMessageTemplate** msg_template ) // outputs + LLMessageTemplate** msg_template, BOOL custom) + // { const U8* header = buffer + LL_PACKET_ID_SIZE; @@ -491,6 +494,9 @@ BOOL LLTemplateMessageReader::decodeTemplate( } else // bogus packet received (too short) { + // + if(!custom) + // llwarns << "Packet with unusable length received (too short): " << buffer_size << llendl; return(FALSE); @@ -503,9 +509,16 @@ BOOL LLTemplateMessageReader::decodeTemplate( } else { + // + if(!custom) + { + // llwarns << "Message #" << std::hex << num << std::dec << " received but not registered!" << llendl; gMessageSystem->callExceptionFunc(MX_UNREGISTERED_MESSAGE); + // + } + // return(FALSE); } @@ -532,7 +545,8 @@ void LLTemplateMessageReader::logRanOffEndOfPacket( const LLHost& host, const S3 } // decode a given message -BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender ) +BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, BOOL custom) +// { llassert( mReceiveSize >= 0 ); llassert( mCurrentRMessageTemplate); @@ -594,6 +608,9 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender } else { + // + if(!custom) + // llerrs << "Unknown block type" << llendl; return FALSE; } @@ -640,6 +657,9 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender if ((decode_pos + data_size) > mReceiveSize) { + // + if(!custom) + // logRanOffEndOfPacket(sender, decode_pos, data_size); // default to 0 length variable blocks @@ -676,6 +696,9 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender // so, copy data pointer and set data size to fixed size if ((decode_pos + mvci.getSize()) > mReceiveSize) { + // + if(!custom) + // logRanOffEndOfPacket(sender, decode_pos, mvci.getSize()); // default to 0s. @@ -703,7 +726,10 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender lldebugs << "Empty message '" << mCurrentRMessageTemplate->mName << "' (no blocks)" << llendl; return FALSE; } - + + // + if(!custom) + // { static LLTimer decode_timer; @@ -756,14 +782,26 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender return TRUE; } +// +LLMessageTemplate* LLTemplateMessageReader::getTemplate() +{ + return mCurrentRMessageTemplate; +} +// + BOOL LLTemplateMessageReader::validateMessage(const U8* buffer, S32 buffer_size, const LLHost& sender, - bool trusted) + bool trusted, + BOOL custom) { mReceiveSize = buffer_size; - BOOL valid = decodeTemplate(buffer, buffer_size, &mCurrentRMessageTemplate ); - if(valid) + // + //BOOL valid = decodeTemplate(buffer, buffer_size, &mCurrentRMessageTemplate ); + BOOL valid = decodeTemplate(buffer, buffer_size, &mCurrentRMessageTemplate, custom ); + //if(result) + if(valid && !custom) + // { mCurrentRMessageTemplate->mReceiveCount++; //lldebugs << "MessageRecvd:" diff --git a/linden/indra/llmessage/lltemplatemessagereader.h b/linden/indra/llmessage/lltemplatemessagereader.h index ab06ab433..0eef93a76 100644 --- a/linden/indra/llmessage/lltemplatemessagereader.h +++ b/linden/indra/llmessage/lltemplatemessagereader.h @@ -102,28 +102,32 @@ class LLTemplateMessageReader : public LLMessageReader virtual const char* getMessageName() const; virtual S32 getMessageSize() const; + // + LLMessageTemplate* getTemplate(); + // + virtual void copyToBuilder(LLMessageBuilder&) const; BOOL validateMessage(const U8* buffer, S32 buffer_size, - const LLHost& sender, bool trusted = false); + const LLHost& sender, bool trusted = false, BOOL custom = FALSE); BOOL readMessage(const U8* buffer, const LLHost& sender); bool isTrusted() const; bool isBanned(bool trusted_source) const; bool isUdpBanned() const; + + BOOL decodeData(const U8* buffer, const LLHost& sender, BOOL custom = FALSE); + + BOOL decodeTemplate(const U8* buffer, S32 buffer_size, // inputs + LLMessageTemplate** msg_template, BOOL custom = FALSE); // outputs private: void getData(const char *blockname, const char *varname, void *datap, S32 size = 0, S32 blocknum = 0, S32 max_size = S32_MAX); - BOOL decodeTemplate(const U8* buffer, S32 buffer_size, // inputs - LLMessageTemplate** msg_template ); // outputs - void logRanOffEndOfPacket( const LLHost& host, const S32 where, const S32 wanted ); - BOOL decodeData(const U8* buffer, const LLHost& sender ); - S32 mReceiveSize; LLMessageTemplate* mCurrentRMessageTemplate; LLMsgData* mCurrentRMessageData; diff --git a/linden/indra/llmessage/llurlrequest.cpp b/linden/indra/llmessage/llurlrequest.cpp index 46e976fe3..87f011643 100644 --- a/linden/indra/llmessage/llurlrequest.cpp +++ b/linden/indra/llmessage/llurlrequest.cpp @@ -45,6 +45,7 @@ #include "llstring.h" #include "apr_env.h" #include "llapr.h" +#include "llscopedvolatileaprpool.h" static const U32 HTTP_STATUS_PIPE_ERROR = 499; /** @@ -161,27 +162,31 @@ void LLURLRequest::setCallback(LLURLRequestComplete* callback) // is called with use_proxy = FALSE void LLURLRequest::useProxy(bool use_proxy) { - static char *env_proxy; + static std::string env_proxy; - if (use_proxy && (env_proxy == NULL)) + if (use_proxy && env_proxy.empty()) { - apr_status_t status; - LLAPRPool pool; - status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool()); + char* env_proxy_str; + LLScopedVolatileAPRPool scoped_pool; + apr_status_t status = apr_env_get(&env_proxy_str, "ALL_PROXY", scoped_pool); if (status != APR_SUCCESS) { - status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool()); + status = apr_env_get(&env_proxy_str, "http_proxy", scoped_pool); } if (status != APR_SUCCESS) { - use_proxy = FALSE; + use_proxy = false; } + else + { + // env_proxy_str is stored in the scoped_pool, so we have to make a copy. + env_proxy = env_proxy_str; + } } + lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = \"" << env_proxy << "\"" << llendl; - lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << llendl; - - if (env_proxy && use_proxy) + if (use_proxy) { mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy); } diff --git a/linden/indra/llmessage/message.cpp b/linden/indra/llmessage/message.cpp index 78af35bf6..53036bcf6 100644 --- a/linden/indra/llmessage/message.cpp +++ b/linden/indra/llmessage/message.cpp @@ -86,6 +86,7 @@ #include "v3math.h" #include "v4math.h" #include "lltransfertargetvfile.h" +#include "llmessagelog.h" // Constants //const char* MESSAGE_LOG_FILENAME = "message.log"; @@ -102,8 +103,10 @@ std::string get_shared_secret(); class LLMessagePollInfo { public: + LLMessagePollInfo(void) : mPool(LLThread::tldata().mRootPool) { } apr_socket_t *mAPRSocketp; apr_pollfd_t mPollFD; + AIAPRPool mPool; }; namespace @@ -290,20 +293,13 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port, } // LL_DEBUGS("Messaging") << << "*** port: " << mPort << llendl; - // - // Create the data structure that we can poll on - // - if (!gAPRPoolp) - { - LL_ERRS("Messaging") << "No APR pool before message system initialization!" << llendl; - ll_init_apr(); - } + mPollInfop = new LLMessagePollInfo; + apr_socket_t *aprSocketp = NULL; - apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, gAPRPoolp); + apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, mPollInfop->mPool()); - mPollInfop = new LLMessagePollInfo; mPollInfop->mAPRSocketp = aprSocketp; - mPollInfop->mPollFD.p = gAPRPoolp; + mPollInfop->mPollFD.p = mPollInfop->mPool(); mPollInfop->mPollFD.desc_type = APR_POLL_SOCKET; mPollInfop->mPollFD.reqevents = APR_POLLIN; mPollInfop->mPollFD.rtnevents = 0; @@ -524,10 +520,10 @@ LLCircuitData* LLMessageSystem::findCircuit(const LLHost& host, } // Returns TRUE if a valid, on-circuit message has been received. -BOOL LLMessageSystem::checkMessages( S64 frame_count ) +BOOL LLMessageSystem::checkMessages( S64 frame_count, bool faked_message, U8 fake_buffer[MAX_BUFFER_SIZE], LLHost fake_host, S32 fake_size ) { // Pump - BOOL valid_packet = FALSE; + BOOL valid_packet = FALSE; mMessageReader = mTemplateMessageReader; LLTransferTargetVFile::updateQueue(); @@ -557,6 +553,13 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count ) mTrueReceiveSize = mPacketRing.receivePacket(mSocket, (char *)mTrueReceiveBuffer); // If you want to dump all received packets into SecondLife.log, uncomment this //dumpPacketToLog(); + // + if(mTrueReceiveSize && receive_size > (S32) LL_MINIMUM_VALID_PACKET_SIZE) + { + LLMessageLog::log(mLastSender, LLHost(16777343, mPort), buffer, mTrueReceiveSize); + } + // + receive_size = mTrueReceiveSize; mLastSender = mPacketRing.getLastSender(); @@ -1549,6 +1552,12 @@ U32 LLMessageSystem::getOurCircuitCode() return mOurCircuitCode; } +// +LLCircuit* LLMessageSystem::getCircuit() +{ + return &mCircuitInfo; +} + void LLMessageSystem::getCircuitInfo(LLSD& info) const { mCircuitInfo.getInfo(info); diff --git a/linden/indra/llmessage/message.h b/linden/indra/llmessage/message.h index b25b27eb0..e6391d969 100644 --- a/linden/indra/llmessage/message.h +++ b/linden/indra/llmessage/message.h @@ -230,11 +230,14 @@ class LLMessageSystem : public LLMessageSenderInterface typedef std::map message_template_name_map_t; typedef std::map message_template_number_map_t; -private: +// +//private: +// message_template_name_map_t mMessageTemplates; message_template_number_map_t mMessageNumbers; - -public: +// +//public: +// S32 mSystemVersionMajor; S32 mSystemVersionMinor; S32 mSystemVersionPatch; @@ -341,7 +344,7 @@ class LLMessageSystem : public LLMessageSenderInterface bool addCircuitCode(U32 code, const LLUUID& session_id); BOOL poll(F32 seconds); // Number of seconds that we want to block waiting for data, returns if data was received - BOOL checkMessages( S64 frame_count = 0 ); + BOOL checkMessages( S64 frame_count = 0, bool faked_message = false, U8 fake_buffer[MAX_BUFFER_SIZE] = NULL, LLHost fake_host = LLHost(), S32 fake_size = 0 ); void processAcks(); BOOL isMessageFast(const char *msg); @@ -569,6 +572,10 @@ class LLMessageSystem : public LLMessageSenderInterface void showCircuitInfo(); void getCircuitInfo(LLSD& info) const; + // + LLCircuit* getCircuit(); + // + U32 getOurCircuitCode(); void enableCircuit(const LLHost &host, BOOL trusted); @@ -733,6 +740,8 @@ class LLMessageSystem : public LLMessageSenderInterface // This will cause all trust queries to return true until the next message // is read: use with caution! void receivedMessageFromTrustedSender(); + + LLTemplateMessageBuilder* mTemplateMessageBuilder; private: @@ -807,7 +816,6 @@ class LLMessageSystem : public LLMessageSenderInterface TPACKETID mCurrentRecvPacketID; // packet ID of current receive packet (for reporting) LLMessageBuilder* mMessageBuilder; - LLTemplateMessageBuilder* mTemplateMessageBuilder; LLSDMessageBuilder* mLLSDMessageBuilder; LLMessageReader* mMessageReader; LLTemplateMessageReader* mTemplateMessageReader; diff --git a/linden/indra/llmessage/tests/commtest.h b/linden/indra/llmessage/tests/commtest.h new file mode 100644 index 000000000..cf1461ed2 --- /dev/null +++ b/linden/indra/llmessage/tests/commtest.h @@ -0,0 +1,83 @@ +/** + * @file commtest.h + * @author Nat Goodspeed + * @date 2009-01-09 + * @brief + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if ! defined(LL_COMMTEST_H) +#define LL_COMMTEST_H + +#include "networkio.h" +#include "llevents.h" +#include "llsd.h" +#include "llhost.h" +#include "stringize.h" +#include + +/** + * This struct is shared by a couple of standalone comm tests (ADD_COMM_BUILD_TEST). + */ +struct commtest_data +{ + NetworkIO& netio; + LLEventPumps& pumps; + LLEventStream replyPump, errorPump; + LLSD result; + bool success; + LLHost host; + std::string server; + + commtest_data(): + netio(NetworkIO::instance()), + pumps(LLEventPumps::instance()), + replyPump("reply"), + errorPump("error"), + success(false), + host("127.0.0.1", 8000), + server(STRINGIZE("http://" << host.getString() << "/")) + { + replyPump.listen("self", boost::bind(&commtest_data::outcome, this, _1, true)); + errorPump.listen("self", boost::bind(&commtest_data::outcome, this, _1, false)); + } + + bool outcome(const LLSD& _result, bool _success) + { +// std::cout << "commtest_data::outcome(" << _result << ", " << _success << ")\n"; + result = _result; + success = _success; + // Break the wait loop in NetworkIO::pump(), otherwise devs get + // irritated at making the big monolithic test executable take longer + pumps.obtain("done").post(success); + return false; + } +}; + +#endif /* ! defined(LL_COMMTEST_H) */ diff --git a/linden/indra/llmessage/tests/llcurl_stub.cpp b/linden/indra/llmessage/tests/llcurl_stub.cpp new file mode 100644 index 000000000..c73a5659f --- /dev/null +++ b/linden/indra/llmessage/tests/llcurl_stub.cpp @@ -0,0 +1,100 @@ +/** + * @file llcurl_stub.cpp + * @brief stub class to allow unit testing + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llcurl.h" + +LLCurl::Responder::Responder() : mReferenceCount(0) +{ +} + +void LLCurl::Responder::completed(U32 status, std::basic_string, std::allocator > const &reason, + LLSD const& mContent) +{ + if (isGoodStatus(status)) + { + result(mContent); + } + else + { + error(status, reason, mContent); + } +} + +void LLCurl::Responder::completedHeader(unsigned, + std::basic_string, std::allocator > const&, + LLSD const&) +{ +} + +void LLCurl::Responder::completedRaw(unsigned, + std::basic_string, std::allocator > const&, + LLChannelDescriptors const&, + boost::shared_ptr const&) +{ +} + +void LLCurl::Responder::error(unsigned, + std::basic_string, std::allocator > const&, + LLSD const&) +{ +} + +LLCurl::Responder::~Responder () +{ +} + +void LLCurl::Responder::error(unsigned, + std::basic_string, std::allocator > const&) +{ +} + +void LLCurl::Responder::result(LLSD const&) +{ +} + +namespace boost +{ + void intrusive_ptr_add_ref(LLCurl::Responder* p) + { + ++p->mReferenceCount; + } + + void intrusive_ptr_release(LLCurl::Responder* p) + { + if(p && 0 == --p->mReferenceCount) + { + delete p; + } + } +}; + diff --git a/linden/indra/llmessage/tests/llhttpclientadapter_test.cpp b/linden/indra/llmessage/tests/llhttpclientadapter_test.cpp new file mode 100644 index 000000000..7065c9d7e --- /dev/null +++ b/linden/indra/llmessage/tests/llhttpclientadapter_test.cpp @@ -0,0 +1,170 @@ +/** + * @file + * @brief + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llhttpclientadapter.h" + +#include "../test/lltut.h" +#include "llhttpclient.h" +#include "llcurl_stub.cpp" + +float const HTTP_REQUEST_EXPIRY_SECS = 1.0F; + +std::vector get_urls; +std::vector > get_responders; +void LLHTTPClient::get(const std::string& url, boost::intrusive_ptr responder, const LLSD& headers, const F32 timeout) +{ + get_urls.push_back(url); + get_responders.push_back(responder); +} + +std::vector put_urls; +std::vector put_body; +std::vector > put_responders; + +void LLHTTPClient::put(const std::string& url, const LLSD& body, boost::intrusive_ptr responder, const LLSD& headers, const F32 timeout) +{ + put_urls.push_back(url); + put_responders.push_back(responder); + put_body.push_back(body); + +} + + +namespace tut +{ + struct LLHTTPClientAdapterData + { + LLHTTPClientAdapterData() + { + get_urls.clear(); + get_responders.clear(); + put_urls.clear(); + put_responders.clear(); + put_body.clear(); + } + }; + + typedef test_group factory; + typedef factory::object object; +} + +namespace +{ + tut::factory tf("LLHTTPClientAdapterData test"); +} + +namespace tut +{ + // Ensure we can create the object + template<> template<> + void object::test<1>() + { + LLHTTPClientAdapter adapter; + } + + // Does the get pass the appropriate arguments to the LLHTTPClient + template<> template<> + void object::test<2>() + { + LLHTTPClientAdapter adapter; + + boost::intrusive_ptr responder = new LLCurl::Responder(); + + adapter.get("Made up URL", responder); + ensure_equals(get_urls.size(), 1); + ensure_equals(get_urls[0], "Made up URL"); + } + + // Ensure the responder matches the one passed to get + template<> template<> + void object::test<3>() + { + LLHTTPClientAdapter adapter; + boost::intrusive_ptr responder = new LLCurl::Responder(); + + adapter.get("Made up URL", responder); + + ensure_equals(get_responders.size(), 1); + ensure_equals(get_responders[0].get(), responder.get()); + } + + // Ensure the correct url is used in the put + template<> template<> + void object::test<4>() + { + LLHTTPClientAdapter adapter; + + boost::intrusive_ptr responder = new LLCurl::Responder(); + + LLSD body; + body["TestBody"] = "Foobar"; + + adapter.put("Made up URL", body, responder); + ensure_equals(put_urls.size(), 1); + ensure_equals(put_urls[0], "Made up URL"); + } + + // Ensure the correct responder is used by put + template<> template<> + void object::test<5>() + { + LLHTTPClientAdapter adapter; + + boost::intrusive_ptr responder = new LLCurl::Responder(); + + LLSD body; + body["TestBody"] = "Foobar"; + + adapter.put("Made up URL", body, responder); + + ensure_equals(put_responders.size(), 1); + ensure_equals(put_responders[0].get(), responder.get()); + } + + // Ensure the message body is passed through the put properly + template<> template<> + void object::test<6>() + { + LLHTTPClientAdapter adapter; + + boost::intrusive_ptr responder = new LLCurl::Responder(); + + LLSD body; + body["TestBody"] = "Foobar"; + + adapter.put("Made up URL", body, responder); + + ensure_equals(put_body.size(), 1); + ensure_equals(put_body[0]["TestBody"].asString(), "Foobar"); + } +} + diff --git a/linden/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp b/linden/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp new file mode 100644 index 000000000..0cf49c1aa --- /dev/null +++ b/linden/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp @@ -0,0 +1,165 @@ +/** + * @file lltrustedmessageservice_test.cpp + * @brief LLTrustedMessageService unit tests + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "lltemplatemessagedispatcher.h" +#include "lltut.h" + +#include "llhttpnode.h" +#include "llhost.h" +#include "message.h" +#include "llsd.h" + +#include "llhost.cpp" // Needed for copy operator +#include "net.cpp" // Needed by LLHost. + +LLMessageSystem * gMessageSystem = NULL; + +// sensor test doubles +bool gClearRecvWasCalled = false; +void LLMessageSystem::clearReceiveState(void) +{ + gClearRecvWasCalled = true; +} + +char gUdpDispatchedData[MAX_BUFFER_SIZE]; +bool gUdpDispatchWasCalled = false; +BOOL LLTemplateMessageReader::readMessage(const U8* data,class LLHost const &) +{ + gUdpDispatchWasCalled = true; + strcpy(gUdpDispatchedData, reinterpret_cast(data)); + return true; +} + +BOOL gValidateMessage = FALSE; +BOOL LLTemplateMessageReader::validateMessage(const U8*, S32 buffer_size, LLHost const &sender, bool trusted, BOOL custom) +{ + return gValidateMessage; +} + +LLHost host; +const LLHost& LLMessageSystem::getSender() const +{ + return host; +} + +const char* gBinaryTemplateData = "BINARYTEMPLATEDATA"; +void fillVector(std::vector& vector_data, const char* data) +{ + vector_data.resize(strlen(data) + 1); + strcpy(reinterpret_cast(&vector_data[0]), data); +} + +namespace tut +{ + static LLTemplateMessageReader::message_template_number_map_t numberMap; + + struct LLTemplateMessageDispatcherData + { + LLTemplateMessageDispatcherData() + { + mMessageName = "MessageName"; + gUdpDispatchWasCalled = false; + gClearRecvWasCalled = false; + gValidateMessage = FALSE; + mMessage["body"]["binary-template-data"] = std::vector(); + } + + LLSD mMessage; + LLHTTPNode::ResponsePtr mResponsePtr; + std::string mMessageName; + }; + + typedef test_group factory; + typedef factory::object object; +} + +namespace +{ + tut::factory tf("LLTemplateMessageDispatcher test"); +} + +namespace tut +{ + // does an empty message stop processing? + template<> template<> + void object::test<1>() + { + LLTemplateMessageReader* pReader = NULL; + LLTemplateMessageDispatcher t(*pReader); + t.dispatch(mMessageName, mMessage, mResponsePtr); + ensure(! gUdpDispatchWasCalled); + ensure(! gClearRecvWasCalled); + } + + // does the disaptch invoke the udp send method? + template<> template<> + void object::test<2>() + { + LLTemplateMessageReader* pReader = NULL; + LLTemplateMessageDispatcher t(*pReader); + gValidateMessage = TRUE; + std::vector vector_data; + fillVector(vector_data, gBinaryTemplateData); + mMessage["body"]["binary-template-data"] = vector_data; + t.dispatch(mMessageName, mMessage, mResponsePtr); + ensure("udp dispatch was called", gUdpDispatchWasCalled); + } + + // what if the message wasn't valid? We would hope the message gets cleared! + template<> template<> + void object::test<3>() + { + LLTemplateMessageReader* pReader = NULL; + LLTemplateMessageDispatcher t(*pReader); + std::vector vector_data; + fillVector(vector_data, gBinaryTemplateData); + mMessage["body"]["binary-template-data"] = vector_data; + gValidateMessage = FALSE; + t.dispatch(mMessageName, mMessage, mResponsePtr); + ensure("clear received message was called", gClearRecvWasCalled); + } + + // is the binary data passed through correctly? + template<> template<> + void object::test<4>() + { + LLTemplateMessageReader* pReader = NULL; + LLTemplateMessageDispatcher t(*pReader); + gValidateMessage = TRUE; + std::vector vector_data; + fillVector(vector_data, gBinaryTemplateData); + mMessage["body"]["binary-template-data"] = vector_data; + t.dispatch(mMessageName, mMessage, mResponsePtr); + ensure("data couriered correctly", strcmp(gBinaryTemplateData, gUdpDispatchedData) == 0); + } +} + diff --git a/linden/indra/llmessage/tests/lltesthttpclientadapter.cpp b/linden/indra/llmessage/tests/lltesthttpclientadapter.cpp new file mode 100644 index 000000000..6361f1cee --- /dev/null +++ b/linden/indra/llmessage/tests/lltesthttpclientadapter.cpp @@ -0,0 +1,67 @@ +/** + * @file + * @brief + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "lltesthttpclientadapter.h" + +LLTestHTTPClientAdapter::LLTestHTTPClientAdapter() +{ +} + +LLTestHTTPClientAdapter::~LLTestHTTPClientAdapter() +{ +} + +void LLTestHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder) +{ + mGetUrl.push_back(url); + mGetResponder.push_back(responder); +} + +void LLTestHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) +{ + mPutUrl.push_back(url); + mPutBody.push_back(body); + mPutResponder.push_back(responder); +} + +U32 LLTestHTTPClientAdapter::putCalls() const +{ + return mPutUrl.size(); +} + +void LLTestHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) +{ + mGetUrl.push_back(url); + mGetHeaders.push_back(headers); + mGetResponder.push_back(responder); +} + + diff --git a/linden/indra/llmessage/tests/lltesthttpclientadapter.h b/linden/indra/llmessage/tests/lltesthttpclientadapter.h new file mode 100644 index 000000000..ac2afa8ff --- /dev/null +++ b/linden/indra/llmessage/tests/lltesthttpclientadapter.h @@ -0,0 +1,63 @@ +/** + * @file + * @brief + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +/* Macro Definitions */ +#ifndef LL_LLTESTHTTPCLIENTADAPTER_H +#define LL_LLTESTHTTPCLIENTADAPTER_H + + +#include "linden_common.h" +#include "llhttpclientinterface.h" + +class LLTestHTTPClientAdapter : public LLHTTPClientInterface +{ +public: + LLTestHTTPClientAdapter(); + virtual ~LLTestHTTPClientAdapter(); + virtual void get(const std::string& url, LLCurl::ResponderPtr responder); + virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers); + + virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder); + U32 putCalls() const; + + std::vector mPutBody; + std::vector mGetHeaders; + std::vector mPutUrl; + std::vector mGetUrl; + std::vector mPutResponder; + std::vector mGetResponder; +}; + + + +#endif //LL_LLSIMULATORPRESENCESENDER_H + diff --git a/linden/indra/llmessage/tests/lltestmessagesender.cpp b/linden/indra/llmessage/tests/lltestmessagesender.cpp new file mode 100644 index 000000000..5e8a87f6f --- /dev/null +++ b/linden/indra/llmessage/tests/lltestmessagesender.cpp @@ -0,0 +1,44 @@ +/** + * @file + * @brief + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "lltestmessagesender.h" + +LLTestMessageSender::~LLTestMessageSender() +{ +} + + +S32 LLTestMessageSender::sendMessage(const LLHost& host, LLStoredMessagePtr message) +{ + mSendHosts.push_back(host); + mSendMessages.push_back(message); + return 0; +} diff --git a/linden/indra/llmessage/tests/lltestmessagesender.h b/linden/indra/llmessage/tests/lltestmessagesender.h new file mode 100644 index 000000000..f57210e77 --- /dev/null +++ b/linden/indra/llmessage/tests/lltestmessagesender.h @@ -0,0 +1,57 @@ +/** + * @file + * @brief + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +/* Macro Definitions */ +#ifndef LL_LLTESTMESSAGESENDER_H +#define LL_LLTESTMESSAGESENDER_H + + +#include "linden_common.h" +#include "llmessagesenderinterface.h" +#include + + + +class LLTestMessageSender : public LLMessageSenderInterface +{ +public: + virtual ~LLTestMessageSender(); + virtual S32 sendMessage(const LLHost& host, LLStoredMessagePtr message); + + std::vector mSendHosts; + std::vector mSendMessages; +}; + + + +#endif //LL_LLTESTMESSAGESENDER_H + diff --git a/linden/indra/llmessage/tests/lltrustedmessageservice_test.cpp b/linden/indra/llmessage/tests/lltrustedmessageservice_test.cpp new file mode 100644 index 000000000..0a3da4b46 --- /dev/null +++ b/linden/indra/llmessage/tests/lltrustedmessageservice_test.cpp @@ -0,0 +1,146 @@ +/** + * @file lltrustedmessageservice_test.cpp + * @brief LLTrustedMessageService unit tests + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "lltrustedmessageservice.h" +#include "../test/lltut.h" + +#include "llhost.cpp" // LLHost is a value type for test purposes. +#include "net.cpp" // Needed by LLHost. + +#include "message.h" +#include "llmessageconfig.h" + +LLMessageSystem* gMessageSystem = NULL; + +LLMessageConfig::SenderTrust +LLMessageConfig::getSenderTrustedness(const std::string& msg_name) +{ + return LLMessageConfig::NOT_SET; +} + +void LLMessageSystem::receivedMessageFromTrustedSender() +{ +} + +bool LLMessageSystem::isTrustedSender(const LLHost& host) const +{ + return false; +} + +bool LLMessageSystem::isTrustedMessage(const std::string& name) const +{ + return false; +} + +bool messageDispatched = false; +bool messageDispatchedAsBinary = false; +LLSD lastLLSD; +std::string lastMessageName; + +void LLMessageSystem::dispatch(const std::string& msg_name, + const LLSD& message, + LLHTTPNode::ResponsePtr responsep) +{ + messageDispatched = true; + lastLLSD = message; + lastMessageName = msg_name; +} + +void LLMessageSystem::dispatchTemplate(const std::string& msg_name, + const LLSD& message, + LLHTTPNode::ResponsePtr responsep) +{ + lastLLSD = message; + lastMessageName = msg_name; + messageDispatchedAsBinary = true; +} + +namespace tut +{ + struct LLTrustedMessageServiceData + { + LLTrustedMessageServiceData() + { + LLSD emptyLLSD; + lastLLSD = emptyLLSD; + lastMessageName = "uninitialised message name"; + messageDispatched = false; + messageDispatchedAsBinary = false; + } + }; + + typedef test_group factory; + typedef factory::object object; +} + +namespace +{ + tut::factory tf("LLTrustedMessageServiceData test"); +} + +namespace tut +{ + // characterisation tests + + // 1) test that messages get forwarded with names etc. as current behaviour (something like LLMessageSystem::dispatch(name, data...) + + // test llsd messages are sent as normal using LLMessageSystem::dispatch() (eventually) + template<> template<> + void object::test<1>() + { + LLHTTPNode::ResponsePtr response; + LLSD input; + LLSD context; + LLTrustedMessageService adapter; + adapter.post(response, context, input); + // test original ting got called wit nowt, ya get me blood? + ensure_equals(messageDispatched, true); + ensure(lastLLSD.has("body")); + } + + // test that llsd wrapped binary-template-data messages are + // sent via LLMessageSystem::binaryDispatch() or similar + template<> template<> + void object::test<2>() + { + LLHTTPNode::ResponsePtr response; + LLSD input; + input["binary-template-data"] = "10001010110"; //make me a message here. + LLSD context; + LLTrustedMessageService adapter; + + adapter.post(response, context, input); + ensure("check template-binary-data message was dispatched as binary", messageDispatchedAsBinary); + ensure_equals(lastLLSD["body"]["binary-template-data"].asString(), "10001010110"); + // test somit got called with "10001010110" (something like LLMessageSystem::dispatchTemplate(blah)) + } +} diff --git a/linden/indra/llmessage/tests/networkio.h b/linden/indra/llmessage/tests/networkio.h new file mode 100644 index 000000000..0ebe369ea --- /dev/null +++ b/linden/indra/llmessage/tests/networkio.h @@ -0,0 +1,116 @@ +/** + * @file networkio.h + * @author Nat Goodspeed + * @date 2009-01-09 + * @brief + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if ! defined(LL_NETWORKIO_H) +#define LL_NETWORKIO_H + +#include "llmemory.h" // LLSingleton +#include "llapr.h" +#include "llares.h" +#include "llpumpio.h" +#include "llhttpclient.h" + +/***************************************************************************** +* NetworkIO +*****************************************************************************/ +// Doing this initialization in a class constructor makes sense. But we don't +// want to redo it for each different test. Nor do we want to do it at static- +// init time. Use the lazy, on-demand initialization we get from LLSingleton. +class NetworkIO: public LLSingleton +{ +public: + NetworkIO(): + mServicePump(NULL), + mDone(false) + { + ll_init_apr(); + if (! gAPRPoolp) + { + throw std::runtime_error("Can't initialize APR"); + } + + // Create IO Pump to use for HTTP Requests. + mServicePump = new LLPumpIO(gAPRPoolp); + LLHTTPClient::setPump(*mServicePump); + if (ll_init_ares() == NULL || !gAres->isInitialized()) + { + throw std::runtime_error("Can't start DNS resolver"); + } + + // You can interrupt pump() without waiting the full timeout duration + // by posting an event to the LLEventPump named "done". + LLEventPumps::instance().obtain("done").listen("self", + boost::bind(&NetworkIO::done, this, _1)); + } + + bool pump(F32 timeout=10) + { + // Reset the done flag so we don't pop out prematurely + mDone = false; + // Evidently the IO structures underlying LLHTTPClient need to be + // "pumped". Do some stuff normally performed in the viewer's main + // loop. + LLTimer timer; + while (timer.getElapsedTimeF32() < timeout) + { + if (mDone) + { +// std::cout << "NetworkIO::pump(" << timeout << "): breaking loop after " +// << timer.getElapsedTimeF32() << " seconds\n"; + return true; + } + pumpOnce(); + } + return false; + } + + void pumpOnce() + { + gAres->process(); + mServicePump->pump(); + mServicePump->callback(); + } + + bool done(const LLSD&) + { + mDone = true; + return false; + } + +private: + LLPumpIO* mServicePump; + bool mDone; +}; + +#endif /* ! defined(LL_NETWORKIO_H) */ diff --git a/linden/indra/llmessage/tests/test_llsdmessage_peer.py b/linden/indra/llmessage/tests/test_llsdmessage_peer.py new file mode 100644 index 000000000..655169def --- /dev/null +++ b/linden/indra/llmessage/tests/test_llsdmessage_peer.py @@ -0,0 +1,153 @@ +#!/usr/bin/python +"""\ +@file test_llsdmessage_peer.py +@author Nat Goodspeed +@date 2008-10-09 +@brief This script asynchronously runs the executable (with args) specified on + the command line, returning its result code. While that executable is + running, we provide dummy local services for use by C++ tests. + +$LicenseInfo:firstyear=2008&license=viewergpl$ + +Copyright (c) 2008-2009, Linden Research, Inc. + +Second Life Viewer Source Code +The source code in this file ("Source Code") is provided by Linden Lab +to you under the terms of the GNU General Public License, version 2.0 +("GPL"), unless you have obtained a separate licensing agreement +("Other License"), formally executed by you and Linden Lab. Terms of +the GPL can be found in doc/GPL-license.txt in this distribution, or +online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + +There are special exceptions to the terms and conditions of the GPL as +it is applied to this Source Code. View the full text of the exception +in the file doc/FLOSS-exception.txt in this software distribution, or +online at +http://secondlifegrid.net/programs/open_source/licensing/flossexception + +By copying, modifying or distributing this software, you acknowledge +that you have read and understood your obligations described above, +and agree to abide by those obligations. + +ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +COMPLETENESS OR PERFORMANCE. +$/LicenseInfo$ +""" + +import os +import sys +from threading import Thread +from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler +mydir = os.path.dirname(__file__) # expected to be .../indra/llmessage/tests/ +sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python")) +from indra.util.fastest_elementtree import parse as xml_parse +from indra.base import llsd + +def debug(*args): + sys.stdout.writelines(args) + sys.stdout.flush() +# comment out the line below to enable debug output +debug = lambda *args: None + +class TestHTTPRequestHandler(BaseHTTPRequestHandler): + """This subclass of BaseHTTPRequestHandler is to receive and echo + LLSD-flavored messages sent by the C++ LLHTTPClient. + """ + def read(self): + # The following logic is adapted from the library module + # SimpleXMLRPCServer.py. + # Get arguments by reading body of request. + # We read this in chunks to avoid straining + # socket.read(); around the 10 or 15Mb mark, some platforms + # begin to have problems (bug #792570). + try: + size_remaining = int(self.headers["content-length"]) + except (KeyError, ValueError): + return "" + max_chunk_size = 10*1024*1024 + L = [] + while size_remaining: + chunk_size = min(size_remaining, max_chunk_size) + chunk = self.rfile.read(chunk_size) + L.append(chunk) + size_remaining -= len(chunk) + return ''.join(L) + # end of swiped read() logic + + def read_xml(self): + # This approach reads the entire POST data into memory first + return llsd.parse(self.read()) +## # This approach attempts to stream in the LLSD XML from self.rfile, +## # assuming that the underlying XML parser reads its input file +## # incrementally. Unfortunately I haven't been able to make it work. +## tree = xml_parse(self.rfile) +## debug("Finished raw parse\n") +## debug("parsed XML tree %s\n" % tree) +## debug("parsed root node %s\n" % tree.getroot()) +## debug("root node tag %s\n" % tree.getroot().tag) +## return llsd.to_python(tree.getroot()) + + def do_GET(self): + # Of course, don't attempt to read data. + self.answer(dict(reply="success", status=500, + reason="Your GET operation requested failure")) + + def do_POST(self): + # Read the provided POST data. + self.answer(self.read_xml()) + + def answer(self, data): + if "fail" not in self.path: + response = llsd.format_xml(data.get("reply", llsd.LLSD("success"))) + self.send_response(200) + self.send_header("Content-type", "application/llsd+xml") + self.send_header("Content-Length", str(len(response))) + self.end_headers() + self.wfile.write(response) + else: # fail requested + status = data.get("status", 500) + reason = data.get("reason", + self.responses.get(status, + ("fail requested", + "Your request specified failure status %s " + "without providing a reason" % status))[1]) + self.send_error(status, reason) + + def log_request(self, code, size=None): + # For present purposes, we don't want the request splattered onto + # stderr, as it would upset devs watching the test run + pass + + def log_error(self, format, *args): + # Suppress error output as well + pass + +class TestHTTPServer(Thread): + def run(self): + httpd = HTTPServer(('127.0.0.1', 8000), TestHTTPRequestHandler) + debug("Starting HTTP server...\n") + httpd.serve_forever() + +def main(*args): + # Start HTTP server thread. Note that this and all other comm server + # threads should be daemon threads: we'll let them run "forever," + # confident that the whole process will terminate when the main thread + # terminates, which will be when the test executable child process + # terminates. + httpThread = TestHTTPServer(name="httpd") + httpThread.setDaemon(True) + httpThread.start() + # choice of os.spawnv(): + # - [v vs. l] pass a list of args vs. individual arguments, + # - [no p] don't use the PATH because we specifically want to invoke the + # executable passed as our first arg, + # - [no e] child should inherit this process's environment. + debug("Running %s...\n" % (" ".join(args))) + sys.stdout.flush() + rc = os.spawnv(os.P_WAIT, args[0], args) + debug("%s returned %s\n" % (args[0], rc)) + return rc + +if __name__ == "__main__": + sys.exit(main(*sys.argv[1:])) diff --git a/linden/indra/llplugin/CMakeLists.txt b/linden/indra/llplugin/CMakeLists.txt new file mode 100644 index 000000000..7a7f4e583 --- /dev/null +++ b/linden/indra/llplugin/CMakeLists.txt @@ -0,0 +1,83 @@ +# -*- cmake -*- + +project(llplugin) + +include(00-Common) +include(CURL) +include(LLCommon) +include(LLImage) +include(LLMath) +include(LLMessage) +include(LLRender) +include(LLXML) +include(LLWindow) + +include_directories( + ${LLCOMMON_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLMESSAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLXML_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} + ${LLQTWEBKIT_INCLUDE_DIR} + ) + +set(llplugin_SOURCE_FILES + llpluginclassmedia.cpp + llplugincookiestore.cpp + llplugininstance.cpp + llpluginmessage.cpp + llpluginmessagepipe.cpp + llpluginprocesschild.cpp + llpluginprocessparent.cpp + llpluginsharedmemory.cpp + ) + +set(llplugin_HEADER_FILES + CMakeLists.txt + + llpluginclassmedia.h + llpluginclassmediaowner.h + llplugincookiestore.h + llplugininstance.h + llpluginmessage.h + llpluginmessageclasses.h + llpluginmessagepipe.h + llpluginprocesschild.h + llpluginprocessparent.h + llpluginsharedmemory.h + ) + +set_source_files_properties(${llplugin_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + if(WINDOWS) + add_definitions(/FIXED:NO) + else(WINDOWS) # not windows therefore gcc LINUX and DARWIN + add_definitions(-fPIC) + endif(WINDOWS) +endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + +list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES}) + +add_library (llplugin ${llplugin_SOURCE_FILES}) + +add_subdirectory(slplugin) + +# # Add tests +# include(LLAddBuildTest) +# # UNIT TESTS +# SET(llplugin_TEST_SOURCE_FILES +# llplugincookiestore.cpp +# ) +# +# # llplugincookiestore has a dependency on curl, so we need to link the curl library into the test. +# set_source_files_properties( +# llplugincookiestore.cpp +# PROPERTIES +# LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}" +# ) +# +# LL_ADD_PROJECT_UNIT_TESTS(llplugin "${llplugin_TEST_SOURCE_FILES}") diff --git a/linden/indra/llplugin/llpluginclassmedia.cpp b/linden/indra/llplugin/llpluginclassmedia.cpp new file mode 100755 index 000000000..85241bec1 --- /dev/null +++ b/linden/indra/llplugin/llpluginclassmedia.cpp @@ -0,0 +1,1235 @@ +/** + * @file llpluginclassmedia.cpp + * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" +#include "indra_constants.h" + +#include "llpluginclassmedia.h" +#include "llpluginmessageclasses.h" + +#include "llqtwebkit.h" + +static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256; + +static int nextPowerOf2( int value ) +{ + int next_power_of_2 = 1; + while ( next_power_of_2 < value ) + { + next_power_of_2 <<= 1; + } + + return next_power_of_2; +} + +LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner) +{ + mOwner = owner; + mPlugin = NULL; + reset(); + + //debug use + mDeleteOK = true ; +} + + +LLPluginClassMedia::~LLPluginClassMedia() +{ + llassert_always(mDeleteOK) ; + reset(); +} + +bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug) +{ + LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; + LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; + + mPlugin = new LLPluginProcessParent(this); + mPlugin->setSleepTime(mSleepTime); + + // Queue up the media init message -- it will be sent after all the currently queued messages. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); + sendMessage(message); + + mPlugin->init(launcher_filename, plugin_filename, debug); + + return true; +} + + +void LLPluginClassMedia::reset() +{ + if(mPlugin != NULL) + { + delete mPlugin; + mPlugin = NULL; + } + + mTextureParamsReceived = false; + mRequestedTextureDepth = 0; + mRequestedTextureInternalFormat = 0; + mRequestedTextureFormat = 0; + mRequestedTextureType = 0; + mRequestedTextureSwapBytes = false; + mRequestedTextureCoordsOpenGL = false; + mTextureSharedMemorySize = 0; + mTextureSharedMemoryName.clear(); + mDefaultMediaWidth = 0; + mDefaultMediaHeight = 0; + mNaturalMediaWidth = 0; + mNaturalMediaHeight = 0; + mSetMediaWidth = -1; + mSetMediaHeight = -1; + mRequestedMediaWidth = 0; + mRequestedMediaHeight = 0; + mRequestedTextureWidth = 0; + mRequestedTextureHeight = 0; + mFullMediaWidth = 0; + mFullMediaHeight = 0; + mTextureWidth = 0; + mTextureHeight = 0; + mMediaWidth = 0; + mMediaHeight = 0; + mDirtyRect = LLRect::null; + mAutoScaleMedia = false; + mRequestedVolume = 1.0f; + mPriority = PRIORITY_NORMAL; + mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; + mAllowDownsample = false; + mPadding = 0; + mLastMouseX = 0; + mLastMouseY = 0; + mStatus = LLPluginClassMediaOwner::MEDIA_NONE; + mSleepTime = 1.0f / 100.0f; + mCanCut = false; + mCanCopy = false; + mCanPaste = false; + mMediaName.clear(); + mMediaDescription.clear(); + mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); + + // media_browser class + mNavigateURI.clear(); + mNavigateResultCode = -1; + mNavigateResultString.clear(); + mHistoryBackAvailable = false; + mHistoryForwardAvailable = false; + mStatusText.clear(); + mProgressPercent = 0; + mClickURL.clear(); + mClickTarget.clear(); + + // media_time class + mCurrentTime = 0.0f; + mDuration = 0.0f; + mCurrentRate = 0.0f; + mLoadedDuration = 0.0f; +} + +void LLPluginClassMedia::idle(void) +{ + if(mPlugin) + { + mPlugin->idle(); + } + + if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked())) + { + // Can't process a size change at this time + } + else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight)) + { + // Calculate the correct size for the media texture + mRequestedTextureHeight = mRequestedMediaHeight; + if(mPadding < 0) + { + // negative values indicate the plugin wants a power of 2 + mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth); + } + else + { + mRequestedTextureWidth = mRequestedMediaWidth; + + if(mPadding > 1) + { + // Pad up to a multiple of the specified number of bytes per row + int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth; + int pad = rowbytes % mPadding; + if(pad != 0) + { + rowbytes += mPadding - pad; + } + + if(rowbytes % mRequestedTextureDepth == 0) + { + mRequestedTextureWidth = rowbytes / mRequestedTextureDepth; + } + else + { + LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL; + } + } + } + + + // Size change has been requested but not initiated yet. + size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth; + + // Add an extra line for padding, just in case. + newsize += mRequestedTextureWidth * mRequestedTextureDepth; + + if(newsize != mTextureSharedMemorySize) + { + if(!mTextureSharedMemoryName.empty()) + { + // Tell the plugin to remove the old memory segment + mPlugin->removeSharedMemory(mTextureSharedMemoryName); + mTextureSharedMemoryName.clear(); + } + + mTextureSharedMemorySize = newsize; + mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize); + if(!mTextureSharedMemoryName.empty()) + { + void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); + + // clear texture memory to avoid random screen visual fuzz from uninitialized texture data + memset( addr, 0x00, newsize ); + + // We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, + // so it may not be worthwhile. + // mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight); + } + } + + // This is our local indicator that a change is in progress. + mTextureWidth = -1; + mTextureHeight = -1; + mMediaWidth = -1; + mMediaHeight = -1; + + // This invalidates any existing dirty rect. + resetDirty(); + + // Send a size change message to the plugin + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change"); + message.setValue("name", mTextureSharedMemoryName); + message.setValueS32("width", mRequestedMediaWidth); + message.setValueS32("height", mRequestedMediaHeight); + message.setValueS32("texture_width", mRequestedTextureWidth); + message.setValueS32("texture_height", mRequestedTextureHeight); + message.setValueReal("background_r", mBackgroundColor.mV[VX]); + message.setValueReal("background_g", mBackgroundColor.mV[VY]); + message.setValueReal("background_b", mBackgroundColor.mV[VZ]); + message.setValueReal("background_a", mBackgroundColor.mV[VW]); + mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue. + + LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; + } + } + + if(mPlugin && mPlugin->isRunning()) + { + // Send queued messages + while(!mSendQueue.empty()) + { + LLPluginMessage message = mSendQueue.front(); + mSendQueue.pop(); + mPlugin->sendMessage(message); + } + } +} + +int LLPluginClassMedia::getTextureWidth() const +{ + return nextPowerOf2(mTextureWidth); +} + +int LLPluginClassMedia::getTextureHeight() const +{ + return nextPowerOf2(mTextureHeight); +} + +unsigned char* LLPluginClassMedia::getBitsData() +{ + unsigned char *result = NULL; + if((mPlugin != NULL) && !mTextureSharedMemoryName.empty()) + { + result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); + } + return result; +} + +void LLPluginClassMedia::setSize(int width, int height) +{ + if((width > 0) && (height > 0)) + { + mSetMediaWidth = width; + mSetMediaHeight = height; + } + else + { + mSetMediaWidth = -1; + mSetMediaHeight = -1; + } + + setSizeInternal(); +} + +void LLPluginClassMedia::setSizeInternal(void) +{ + if((mSetMediaWidth > 0) && (mSetMediaHeight > 0)) + { + mRequestedMediaWidth = mSetMediaWidth; + mRequestedMediaHeight = mSetMediaHeight; + } + else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0)) + { + mRequestedMediaWidth = mNaturalMediaWidth; + mRequestedMediaHeight = mNaturalMediaHeight; + } + else + { + mRequestedMediaWidth = mDefaultMediaWidth; + mRequestedMediaHeight = mDefaultMediaHeight; + } + + // Save these for size/interest calculations + mFullMediaWidth = mRequestedMediaWidth; + mFullMediaHeight = mRequestedMediaHeight; + + if(mAllowDownsample) + { + switch(mPriority) + { + case PRIORITY_SLIDESHOW: + case PRIORITY_LOW: + // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit + while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) + { + mRequestedMediaWidth /= 2; + mRequestedMediaHeight /= 2; + } + break; + + default: + // Don't adjust texture size + break; + } + } + + if(mAutoScaleMedia) + { + mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); + mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); + } + + if(mRequestedMediaWidth > 2048) + mRequestedMediaWidth = 2048; + + if(mRequestedMediaHeight > 2048) + mRequestedMediaHeight = 2048; +} + +void LLPluginClassMedia::setAutoScale(bool auto_scale) +{ + if(auto_scale != mAutoScaleMedia) + { + mAutoScaleMedia = auto_scale; + setSizeInternal(); + } +} + +bool LLPluginClassMedia::textureValid(void) +{ + if( + !mTextureParamsReceived || + mTextureWidth <= 0 || + mTextureHeight <= 0 || + mMediaWidth <= 0 || + mMediaHeight <= 0 || + mRequestedMediaWidth != mMediaWidth || + mRequestedMediaHeight != mMediaHeight || + getBitsData() == NULL + ) + return false; + + return true; +} + +bool LLPluginClassMedia::getDirty(LLRect *dirty_rect) +{ + bool result = !mDirtyRect.isEmpty(); + + if(dirty_rect != NULL) + { + *dirty_rect = mDirtyRect; + } + + return result; +} + +void LLPluginClassMedia::resetDirty(void) +{ + mDirtyRect = LLRect::null; +} + +std::string LLPluginClassMedia::translateModifiers(MASK modifiers) +{ + std::string result; + + + if(modifiers & MASK_CONTROL) + { + result += "control|"; + } + + if(modifiers & MASK_ALT) + { + result += "alt|"; + } + + if(modifiers & MASK_SHIFT) + { + result += "shift|"; + } + + // TODO: should I deal with platform differences here or in callers? + // TODO: how do we deal with the Mac "command" key? +/* + if(modifiers & MASK_SOMETHING) + { + result += "meta|"; + } +*/ + return result; +} + +void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers) +{ + if(type == MOUSE_EVENT_MOVE) + { + if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked()) + { + // Don't queue up mouse move events that can't be delivered. + return; + } + + if((x == mLastMouseX) && (y == mLastMouseY)) + { + // Don't spam unnecessary mouse move events. + return; + } + + mLastMouseX = x; + mLastMouseY = y; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event"); + std::string temp; + switch(type) + { + case MOUSE_EVENT_DOWN: temp = "down"; break; + case MOUSE_EVENT_UP: temp = "up"; break; + case MOUSE_EVENT_MOVE: temp = "move"; break; + case MOUSE_EVENT_DOUBLE_CLICK: temp = "double_click"; break; + } + message.setValue("event", temp); + + message.setValueS32("button", button); + + message.setValueS32("x", x); + + // Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it. + if(!mRequestedTextureCoordsOpenGL) + { + // TODO: Should I use mMediaHeight or mRequestedMediaHeight here? + y = mMediaHeight - y; + } + message.setValueS32("y", y); + + message.setValue("modifiers", translateModifiers(modifiers)); + + sendMessage(message); +} + +bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data) +{ + bool result = true; + + // FIXME: + // HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode. + // For now, return false for the ones the webkit plugin won't handle properly. + + switch(key_code) + { + case KEY_BACKSPACE: + case KEY_TAB: + case KEY_RETURN: + case KEY_PAD_RETURN: + case KEY_SHIFT: + case KEY_CONTROL: + case KEY_ALT: + case KEY_CAPSLOCK: + case KEY_ESCAPE: + case KEY_PAGE_UP: + case KEY_PAGE_DOWN: + case KEY_END: + case KEY_HOME: + case KEY_LEFT: + case KEY_UP: + case KEY_RIGHT: + case KEY_DOWN: + case KEY_INSERT: + case KEY_DELETE: + // These will be handled + break; + + default: + // regular ASCII characters will also be handled + if(key_code >= KEY_SPECIAL) + { + // Other "special" codes will not work properly. + result = false; + } + break; + } + + if(result) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); + std::string temp; + switch(type) + { + case KEY_EVENT_DOWN: temp = "down"; break; + case KEY_EVENT_UP: temp = "up"; break; + case KEY_EVENT_REPEAT: temp = "repeat"; break; + } + message.setValue("event", temp); + + message.setValueS32("key", key_code); + + message.setValue("modifiers", translateModifiers(modifiers)); + message.setValueLLSD("native_key_data", native_key_data); + + sendMessage(message); + } + + return result; +} + +void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); + + message.setValueS32("x", x); + message.setValueS32("y", y); + message.setValue("modifiers", translateModifiers(modifiers)); + + sendMessage(message); +} + +bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); + + message.setValue("text", text); + message.setValue("modifiers", translateModifiers(modifiers)); + message.setValueLLSD("native_key_data", native_key_data); + + sendMessage(message); + + return true; +} + +void LLPluginClassMedia::loadURI(const std::string &uri) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri"); + + message.setValue("uri", uri); + + sendMessage(message); +} + +const char* LLPluginClassMedia::priorityToString(EPriority priority) +{ + const char* result = "UNKNOWN"; + switch(priority) + { + case PRIORITY_UNLOADED: result = "unloaded"; break; + case PRIORITY_STOPPED: result = "stopped"; break; + case PRIORITY_HIDDEN: result = "hidden"; break; + case PRIORITY_SLIDESHOW: result = "slideshow"; break; + case PRIORITY_LOW: result = "low"; break; + case PRIORITY_NORMAL: result = "normal"; break; + case PRIORITY_HIGH: result = "high"; break; + } + + return result; +} + +void LLPluginClassMedia::setPriority(EPriority priority) +{ + if(mPriority != priority) + { + mPriority = priority; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); + + std::string priority_string = priorityToString(priority); + switch(priority) + { + case PRIORITY_UNLOADED: + mSleepTime = 1.0f; + break; + case PRIORITY_STOPPED: + mSleepTime = 1.0f; + break; + case PRIORITY_HIDDEN: + mSleepTime = 1.0f; + break; + case PRIORITY_SLIDESHOW: + mSleepTime = 1.0f; + break; + case PRIORITY_LOW: + mSleepTime = 1.0f / 25.0f; + break; + case PRIORITY_NORMAL: + mSleepTime = 1.0f / 50.0f; + break; + case PRIORITY_HIGH: + mSleepTime = 1.0f / 100.0f; + break; + } + + message.setValue("priority", priority_string); + + sendMessage(message); + + if(mPlugin) + { + mPlugin->setSleepTime(mSleepTime); + } + + LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; + + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); + } +} + +void LLPluginClassMedia::setLowPrioritySizeLimit(int size) +{ + int power = nextPowerOf2(size); + if(mLowPrioritySizeLimit != power) + { + mLowPrioritySizeLimit = power; + + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); + } +} + +F64 LLPluginClassMedia::getCPUUsage() +{ + F64 result = 0.0f; + + if(mPlugin) + { + result = mPlugin->getCPUUsage(); + } + + return result; +} + +void LLPluginClassMedia::cut() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); + sendMessage(message); +} + +void LLPluginClassMedia::copy() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy"); + sendMessage(message); +} + +void LLPluginClassMedia::paste() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste"); + sendMessage(message); +} + +void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path"); + message.setValue("path", user_data_path); + sendMessage(message); +} + +void LLPluginClassMedia::setLanguageCode(const std::string &language_code) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code"); + message.setValue("language", language_code); + sendMessage(message); +} + +void LLPluginClassMedia::setPluginsEnabled(const bool enabled) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled"); + message.setValueBoolean("enable", enabled); + sendMessage(message); +} + +void LLPluginClassMedia::setJavascriptEnabled(const bool enabled) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled"); + message.setValueBoolean("enable", enabled); + sendMessage(message); +} + +/* virtual */ +void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) +{ + std::string message_class = message.getClass(); + + if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + std::string message_name = message.getName(); + if(message_name == "texture_params") + { + mRequestedTextureDepth = message.getValueS32("depth"); + mRequestedTextureInternalFormat = message.getValueU32("internalformat"); + mRequestedTextureFormat = message.getValueU32("format"); + mRequestedTextureType = message.getValueU32("type"); + mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes"); + mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl"); + + // These two are optional, and will default to 0 if they're not specified. + mDefaultMediaWidth = message.getValueS32("default_width"); + mDefaultMediaHeight = message.getValueS32("default_height"); + + mAllowDownsample = message.getValueBoolean("allow_downsample"); + mPadding = message.getValueS32("padding"); + + setSizeInternal(); + + mTextureParamsReceived = true; + } + else if(message_name == "updated") + { + if(message.hasValue("left")) + { + LLRect newDirtyRect; + newDirtyRect.mLeft = message.getValueS32("left"); + newDirtyRect.mTop = message.getValueS32("top"); + newDirtyRect.mRight = message.getValueS32("right"); + newDirtyRect.mBottom = message.getValueS32("bottom"); + + // The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion. + // If they're backwards, swap them. + if(newDirtyRect.mTop < newDirtyRect.mBottom) + { + S32 temp = newDirtyRect.mTop; + newDirtyRect.mTop = newDirtyRect.mBottom; + newDirtyRect.mBottom = temp; + } + + if(mDirtyRect.isEmpty()) + { + mDirtyRect = newDirtyRect; + } + else + { + mDirtyRect.unionWith(newDirtyRect); + } + + LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" + << newDirtyRect.mLeft << ", " + << newDirtyRect.mTop << ", " + << newDirtyRect.mRight << ", " + << newDirtyRect.mBottom << "), new dirty rect is: (" + << mDirtyRect.mLeft << ", " + << mDirtyRect.mTop << ", " + << mDirtyRect.mRight << ", " + << mDirtyRect.mBottom << ")" + << LL_ENDL; + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED); + } + + + bool time_duration_updated = false; + int previous_percent = mProgressPercent; + + if(message.hasValue("current_time")) + { + mCurrentTime = message.getValueReal("current_time"); + time_duration_updated = true; + } + if(message.hasValue("duration")) + { + mDuration = message.getValueReal("duration"); + time_duration_updated = true; + } + + if(message.hasValue("current_rate")) + { + mCurrentRate = message.getValueReal("current_rate"); + } + + if(message.hasValue("loaded_duration")) + { + mLoadedDuration = message.getValueReal("loaded_duration"); + time_duration_updated = true; + } + else + { + // If the message doesn't contain a loaded_duration param, assume it's equal to duration + mLoadedDuration = mDuration; + } + + // Calculate a percentage based on the loaded duration and total duration. + if(mDuration != 0.0f) // Don't divide by zero. + { + mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration); + } + + if(time_duration_updated) + { + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED); + } + + if(previous_percent != mProgressPercent) + { + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); + } + } + else if(message_name == "media_status") + { + std::string status = message.getValue("status"); + + LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL; + + if(status == "loading") + { + mStatus = LLPluginClassMediaOwner::MEDIA_LOADING; + } + else if(status == "loaded") + { + mStatus = LLPluginClassMediaOwner::MEDIA_LOADED; + } + else if(status == "error") + { + mStatus = LLPluginClassMediaOwner::MEDIA_ERROR; + } + else if(status == "playing") + { + mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING; + } + else if(status == "paused") + { + mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED; + } + else if(status == "done") + { + mStatus = LLPluginClassMediaOwner::MEDIA_DONE; + } + else + { + // empty string or any unknown string + mStatus = LLPluginClassMediaOwner::MEDIA_NONE; + } + } + else if(message_name == "size_change_request") + { + S32 width = message.getValueS32("width"); + S32 height = message.getValueS32("height"); + std::string name = message.getValue("name"); + + // TODO: check that name matches? + mNaturalMediaWidth = width; + mNaturalMediaHeight = height; + + setSizeInternal(); + } + else if(message_name == "size_change_response") + { + std::string name = message.getValue("name"); + + // TODO: check that name matches? + + mTextureWidth = message.getValueS32("texture_width"); + mTextureHeight = message.getValueS32("texture_height"); + mMediaWidth = message.getValueS32("width"); + mMediaHeight = message.getValueS32("height"); + + // This invalidates any existing dirty rect. + resetDirty(); + + // TODO: should we verify that the plugin sent back the right values? + // Two size changes in a row may cause them to not match, due to queueing, etc. + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED); + } + else if(message_name == "cursor_changed") + { + mCursorName = message.getValue("name"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED); + } + else if(message_name == "edit_state") + { + if(message.hasValue("cut")) + { + mCanCut = message.getValueBoolean("cut"); + } + if(message.hasValue("copy")) + { + mCanCopy = message.getValueBoolean("copy"); + } + if(message.hasValue("paste")) + { + mCanPaste = message.getValueBoolean("paste"); + } + } + else if(message_name == "name_text") + { + mMediaName = message.getValue("name"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED); + } + else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) + { + std::string message_name = message.getName(); + if(message_name == "navigate_begin") + { + mNavigateURI = message.getValue("uri"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN); + } + else if(message_name == "navigate_complete") + { + mNavigateURI = message.getValue("uri"); + mNavigateResultCode = message.getValueS32("result_code"); + mNavigateResultString = message.getValue("result_string"); + mHistoryBackAvailable = message.getValueBoolean("history_back_available"); + mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE); + } + else if(message_name == "progress") + { + mProgressPercent = message.getValueS32("percent"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); + } + else if(message_name == "status_text") + { + mStatusText = message.getValue("status"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED); + } + else if(message_name == "location_changed") + { + mLocation = message.getValue("uri"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED); + } + else if(message_name == "click_href") + { + mClickURL = message.getValue("uri"); + mClickTarget = message.getValue("target"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF); + } + else if(message_name == "click_nofollow") + { + mClickURL = message.getValue("uri"); + mClickTarget.clear(); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW); + } + else if(message_name == "cookie_set") + { + if(mOwner) + { + mOwner->handleCookieSet(this, message.getValue("cookie")); + } + } + else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + std::string message_name = message.getName(); + + // This class hasn't defined any incoming messages yet. +// if(message_name == "message_name") +// { +// } +// else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + +} + +/* virtual */ +void LLPluginClassMedia::pluginLaunchFailed() +{ + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH); +} + +/* virtual */ +void LLPluginClassMedia::pluginDied() +{ + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); +} + +void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event) +{ + if(mOwner) + { + mOwner->handleMediaEvent(this, event); + } +} + +void LLPluginClassMedia::sendMessage(const LLPluginMessage &message) +{ + if(mPlugin && mPlugin->isRunning()) + { + mPlugin->sendMessage(message); + } + else + { + // The plugin isn't set up yet -- queue this message to be sent after initialization. + mSendQueue.push(message); + } +} + +//////////////////////////////////////////////////////////// +// MARK: media_browser class functions +bool LLPluginClassMedia::pluginSupportsMediaBrowser(void) +{ + std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER); + return !version.empty(); +} + +void LLPluginClassMedia::focus(bool focused) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus"); + + message.setValueBoolean("focused", focused); + + sendMessage(message); +} + +void LLPluginClassMedia::clear_cache() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache"); + sendMessage(message); +} + +void LLPluginClassMedia::clear_cookies() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies"); + sendMessage(message); +} + +void LLPluginClassMedia::set_cookies(const std::string &cookies) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies"); + message.setValue("cookies", cookies); + sendMessage(message); +} + +void LLPluginClassMedia::enable_cookies(bool enable) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies"); + message.setValueBoolean("enable", enable); + sendMessage(message); +} + +void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup"); + + message.setValueBoolean("enable", enable); + message.setValue("host", host); + message.setValueS32("port", port); + + sendMessage(message); +} + +void LLPluginClassMedia::browse_stop() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop"); + sendMessage(message); +} + +void LLPluginClassMedia::browse_reload(bool ignore_cache) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload"); + + message.setValueBoolean("ignore_cache", ignore_cache); + + sendMessage(message); +} + +void LLPluginClassMedia::browse_forward() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward"); + sendMessage(message); +} + +void LLPluginClassMedia::browse_back() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back"); + sendMessage(message); +} + +void LLPluginClassMedia::set_status_redirect(int code, const std::string &url) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_status_redirect"); + + message.setValueS32("code", code); + message.setValue("url", url); + + sendMessage(message); +} + +void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); + + message.setValue("user_agent", user_agent); + + sendMessage(message); +} + +void LLPluginClassMedia::crashPlugin() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); + + sendMessage(message); +} + +void LLPluginClassMedia::hangPlugin() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang"); + + sendMessage(message); +} + + +//////////////////////////////////////////////////////////// +// MARK: media_time class functions +bool LLPluginClassMedia::pluginSupportsMediaTime(void) +{ + std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME); + return !version.empty(); +} + +void LLPluginClassMedia::stop() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop"); + sendMessage(message); +} + +void LLPluginClassMedia::start(float rate) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start"); + + message.setValueReal("rate", rate); + + sendMessage(message); +} + +void LLPluginClassMedia::pause() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause"); + sendMessage(message); +} + +void LLPluginClassMedia::seek(float time) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek"); + + message.setValueReal("time", time); + + sendMessage(message); +} + +void LLPluginClassMedia::setLoop(bool loop) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop"); + + message.setValueBoolean("loop", loop); + + sendMessage(message); +} + +void LLPluginClassMedia::setVolume(float volume) +{ + if(volume != mRequestedVolume) + { + mRequestedVolume = volume; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume"); + + message.setValueReal("volume", volume); + + sendMessage(message); + } +} + +float LLPluginClassMedia::getVolume() +{ + return mRequestedVolume; +} + +void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history) +{ + // Send URL history to plugin + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history"); + message.setValueLLSD("history", url_history); + sendMessage(message); + + LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL; +} + diff --git a/linden/indra/llplugin/llpluginclassmedia.h b/linden/indra/llplugin/llpluginclassmedia.h new file mode 100755 index 000000000..0004971c6 --- /dev/null +++ b/linden/indra/llplugin/llpluginclassmedia.h @@ -0,0 +1,377 @@ +/** + * @file llpluginclassmedia.h + * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LL_LLPLUGINCLASSMEDIA_H +#define LL_LLPLUGINCLASSMEDIA_H + +#include "llgltypes.h" +#include "llpluginprocessparent.h" +#include "llrect.h" +#include "llpluginclassmediaowner.h" +#include +#include "v4color.h" + +class LLPluginClassMedia : public LLPluginProcessParentOwner +{ + LOG_CLASS(LLPluginClassMedia); +public: + LLPluginClassMedia(LLPluginClassMediaOwner *owner); + virtual ~LLPluginClassMedia(); + + // local initialization, called by the media manager when creating a source + virtual bool init(const std::string &launcher_filename, + const std::string &plugin_filename, + bool debug); + + // undoes everything init() didm called by the media manager when destroying a source + virtual void reset(); + + void idle(void); + + // All of these may return 0 or an actual valid value. + // Callers need to check the return for 0, and not use the values in that case. + int getWidth() const { return (mMediaWidth > 0) ? mMediaWidth : 0; }; + int getHeight() const { return (mMediaHeight > 0) ? mMediaHeight : 0; }; + int getNaturalWidth() const { return mNaturalMediaWidth; }; + int getNaturalHeight() const { return mNaturalMediaHeight; }; + int getSetWidth() const { return mSetMediaWidth; }; + int getSetHeight() const { return mSetMediaHeight; }; + int getBitsWidth() const { return (mTextureWidth > 0) ? mTextureWidth : 0; }; + int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; }; + int getTextureWidth() const; + int getTextureHeight() const; + int getFullWidth() const { return mFullMediaWidth; }; + int getFullHeight() const { return mFullMediaHeight; }; + + // This may return NULL. Callers need to check for and handle this case. + unsigned char* getBitsData(); + + // gets the format details of the texture data + // These may return 0 if they haven't been set up yet. The caller needs to detect this case. + int getTextureDepth() const { return mRequestedTextureDepth; }; + int getTextureFormatInternal() const { return mRequestedTextureInternalFormat; }; + int getTextureFormatPrimary() const { return mRequestedTextureFormat; }; + int getTextureFormatType() const { return mRequestedTextureType; }; + bool getTextureFormatSwapBytes() const { return mRequestedTextureSwapBytes; }; + bool getTextureCoordsOpenGL() const { return mRequestedTextureCoordsOpenGL; }; + + void setSize(int width, int height); + void setAutoScale(bool auto_scale); + + void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; + + // Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent. + // This will initially be false, and will also be false for some time after setSize while the resize is processed. + // Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values + // until you call idle() again. + bool textureValid(void); + + bool getDirty(LLRect *dirty_rect = NULL); + void resetDirty(void); + + typedef enum + { + MOUSE_EVENT_DOWN, + MOUSE_EVENT_UP, + MOUSE_EVENT_MOVE, + MOUSE_EVENT_DOUBLE_CLICK + }EMouseEventType; + + void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers); + + typedef enum + { + KEY_EVENT_DOWN, + KEY_EVENT_UP, + KEY_EVENT_REPEAT + }EKeyEventType; + + bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); + + void scrollEvent(int x, int y, MASK modifiers); + + // Text may be unicode (utf8 encoded) + bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data); + + void loadURI(const std::string &uri); + + // "Loading" means uninitialized or any state prior to fully running (processing commands) + bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; }; + + // "Running" means the steady state -- i.e. processing messages + bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; }; + + // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally) + bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; }; + + std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); }; + + bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; }; + void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); }; + + // Inherited from LLPluginProcessParentOwner + /* virtual */ void receivePluginMessage(const LLPluginMessage &message); + /* virtual */ void pluginLaunchFailed(); + /* virtual */ void pluginDied(); + + + typedef enum + { + PRIORITY_UNLOADED, // media plugin isn't even loaded. + PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. + PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. + PRIORITY_SLIDESHOW, // media is in the far distance, updates very infrequently + PRIORITY_LOW, // media is in the distance, may be rendered at reduced size + PRIORITY_NORMAL, // normal (default) priority + PRIORITY_HIGH // media has user focus and/or is taking up most of the screen + }EPriority; + + static const char* priorityToString(EPriority priority); + void setPriority(EPriority priority); + void setLowPrioritySizeLimit(int size); + + F64 getCPUUsage(); + + // Valid after a MEDIA_EVENT_CURSOR_CHANGED event + std::string getCursorName() const { return mCursorName; }; + + LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; } + + void cut(); + bool canCut() const { return mCanCut; }; + + void copy(); + bool canCopy() const { return mCanCopy; }; + + void paste(); + bool canPaste() const { return mCanPaste; }; + + // These can be called before init(), and they will be queued and sent before the media init message. + void setUserDataPath(const std::string &user_data_path); + void setLanguageCode(const std::string &language_code); + void setPluginsEnabled(const bool enabled); + void setJavascriptEnabled(const bool enabled); + + /////////////////////////////////// + // media browser class functions + bool pluginSupportsMediaBrowser(void); + + void focus(bool focused); + void clear_cache(); + void clear_cookies(); + void set_cookies(const std::string &cookies); + void enable_cookies(bool enable); + void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0); + void browse_stop(); + void browse_reload(bool ignore_cache = false); + void browse_forward(); + void browse_back(); + void set_status_redirect(int code, const std::string &url); + void setBrowserUserAgent(const std::string& user_agent); + + // This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE + std::string getNavigateURI() const { return mNavigateURI; }; + + // These are valid after MEDIA_EVENT_NAVIGATE_COMPLETE + S32 getNavigateResultCode() const { return mNavigateResultCode; }; + std::string getNavigateResultString() const { return mNavigateResultString; }; + bool getHistoryBackAvailable() const { return mHistoryBackAvailable; }; + bool getHistoryForwardAvailable() const { return mHistoryForwardAvailable; }; + + // This is valid after MEDIA_EVENT_PROGRESS_UPDATED + int getProgressPercent() const { return mProgressPercent; }; + + // This is valid after MEDIA_EVENT_STATUS_TEXT_CHANGED + std::string getStatusText() const { return mStatusText; }; + + // This is valid after MEDIA_EVENT_LOCATION_CHANGED + std::string getLocation() const { return mLocation; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_HREF or MEDIA_EVENT_CLICK_LINK_NOFOLLOW + std::string getClickURL() const { return mClickURL; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_HREF + std::string getClickTarget() const { return mClickTarget; }; + + + std::string getMediaName() const { return mMediaName; }; + std::string getMediaDescription() const { return mMediaDescription; }; + + // Crash the plugin. If you use this outside of a testbed, you will be punished. + void crashPlugin(); + + // Hang the plugin. If you use this outside of a testbed, you will be punished. + void hangPlugin(); + + /////////////////////////////////// + // media time class functions + bool pluginSupportsMediaTime(void); + void stop(); + void start(float rate = 0.0f); + void pause(); + void seek(float time); + void setLoop(bool loop); + void setVolume(float volume); + float getVolume(); + + F64 getCurrentTime(void) const { return mCurrentTime; }; + F64 getDuration(void) const { return mDuration; }; + F64 getCurrentPlayRate(void) { return mCurrentRate; }; + F64 getLoadedDuration(void) const { return mLoadedDuration; }; + + // Initialize the URL history of the plugin by sending + // "init_history" message + void initializeUrlHistory(const LLSD& url_history); + +protected: + + LLPluginClassMediaOwner *mOwner; + + // Notify this object's owner that an event has occurred. + void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event); + + void sendMessage(const LLPluginMessage &message); // Send message internally, either queueing or sending directly. + std::queue mSendQueue; // Used to queue messages while the plugin initializes. + + void setSizeInternal(void); + + bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true + S32 mRequestedTextureDepth; + LLGLenum mRequestedTextureInternalFormat; + LLGLenum mRequestedTextureFormat; + LLGLenum mRequestedTextureType; + bool mRequestedTextureSwapBytes; + bool mRequestedTextureCoordsOpenGL; + + std::string mTextureSharedMemoryName; + size_t mTextureSharedMemorySize; + + // True to scale requested media up to the full size of the texture (i.e. next power of two) + bool mAutoScaleMedia; + + // default media size for the plugin, from the texture_params message. + int mDefaultMediaWidth; + int mDefaultMediaHeight; + + // Size that has been requested by the plugin itself + int mNaturalMediaWidth; + int mNaturalMediaHeight; + + // Size that has been requested with setSize() + int mSetMediaWidth; + int mSetMediaHeight; + + // Full calculated media size (before auto-scale and downsample calculations) + int mFullMediaWidth; + int mFullMediaHeight; + + // Actual media size being set (after auto-scale) + int mRequestedMediaWidth; + int mRequestedMediaHeight; + + // Texture size calculated from actual media size + int mRequestedTextureWidth; + int mRequestedTextureHeight; + + // Size that the plugin has acknowledged + int mTextureWidth; + int mTextureHeight; + int mMediaWidth; + int mMediaHeight; + + float mRequestedVolume; + + // Priority of this media stream + EPriority mPriority; + int mLowPrioritySizeLimit; + + bool mAllowDownsample; + int mPadding; + + + LLPluginProcessParent *mPlugin; + + LLRect mDirtyRect; + + std::string translateModifiers(MASK modifiers); + + std::string mCursorName; + int mLastMouseX; + int mLastMouseY; + + LLPluginClassMediaOwner::EMediaStatus mStatus; + + F64 mSleepTime; + + bool mCanCut; + bool mCanCopy; + bool mCanPaste; + + std::string mMediaName; + std::string mMediaDescription; + + LLColor4 mBackgroundColor; + + ///////////////////////////////////////// + // media_browser class + std::string mNavigateURI; + S32 mNavigateResultCode; + std::string mNavigateResultString; + bool mHistoryBackAvailable; + bool mHistoryForwardAvailable; + std::string mStatusText; + int mProgressPercent; + std::string mLocation; + std::string mClickURL; + std::string mClickTarget; + + ///////////////////////////////////////// + // media_time class + F64 mCurrentTime; + F64 mDuration; + F64 mCurrentRate; + F64 mLoadedDuration; + +//-------------------------------------- + //debug use only + // +private: + bool mDeleteOK ; +public: + void setDeleteOK(bool flag) { mDeleteOK = flag ;} +//-------------------------------------- +}; + +#endif // LL_LLPLUGINCLASSMEDIA_H diff --git a/linden/indra/llplugin/llpluginclassmediaowner.h b/linden/indra/llplugin/llpluginclassmediaowner.h new file mode 100755 index 000000000..9d1f35220 --- /dev/null +++ b/linden/indra/llplugin/llpluginclassmediaowner.h @@ -0,0 +1,87 @@ +/** + * @file llpluginclassmediaowner.h + * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LL_LLPLUGINCLASSMEDIAOWNER_H +#define LL_LLPLUGINCLASSMEDIAOWNER_H + +#include "llpluginprocessparent.h" +#include "llrect.h" +#include + +class LLPluginClassMedia; +class LLPluginCookieStore; + +class LLPluginClassMediaOwner +{ +public: + typedef enum + { + MEDIA_EVENT_CONTENT_UPDATED, // contents/dirty rect have updated + MEDIA_EVENT_TIME_DURATION_UPDATED, // current time and/or duration have updated + MEDIA_EVENT_SIZE_CHANGED, // media size has changed + MEDIA_EVENT_CURSOR_CHANGED, // plugin has requested a cursor change + + MEDIA_EVENT_NAVIGATE_BEGIN, // browser has begun navigation + MEDIA_EVENT_NAVIGATE_COMPLETE, // browser has finished navigation + MEDIA_EVENT_PROGRESS_UPDATED, // browser has updated loading progress + MEDIA_EVENT_STATUS_TEXT_CHANGED, // browser has updated the status text + MEDIA_EVENT_NAME_CHANGED, // browser has updated the name of the media (typically tag) + MEDIA_EVENT_LOCATION_CHANGED, // browser location (URL) has changed (maybe due to internal navagation/frames/etc) + MEDIA_EVENT_CLICK_LINK_HREF, // I'm not entirely sure what the semantics of these two are + MEDIA_EVENT_CLICK_LINK_NOFOLLOW, + + MEDIA_EVENT_PLUGIN_FAILED_LAUNCH, // The plugin failed to launch + MEDIA_EVENT_PLUGIN_FAILED // The plugin died unexpectedly + + } EMediaEvent; + + typedef enum + { + MEDIA_NONE, // Uninitialized -- no useful state + MEDIA_LOADING, // loading or navigating + MEDIA_LOADED, // navigation/preroll complete + MEDIA_ERROR, // navigation/preroll failed + MEDIA_PLAYING, // playing (only for time-based media) + MEDIA_PAUSED, // paused (only for time-based media) + MEDIA_DONE // finished playing (only for time-based media) + + } EMediaStatus; + + virtual ~LLPluginClassMediaOwner() {}; + virtual void handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent /*event*/) {}; + virtual void handleCookieSet(LLPluginClassMedia* /*self*/, const std::string &/*cookie*/) {}; +}; + +#endif // LL_LLPLUGINCLASSMEDIAOWNER_H diff --git a/linden/indra/llplugin/llplugincookiestore.cpp b/linden/indra/llplugin/llplugincookiestore.cpp new file mode 100644 index 000000000..283ba356f --- /dev/null +++ b/linden/indra/llplugin/llplugincookiestore.cpp @@ -0,0 +1,671 @@ +/** + * @file llplugincookiestore.cpp + * @brief LLPluginCookieStore provides central storage for http cookies used by plugins + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" +#include "indra_constants.h" + +#include "llplugincookiestore.h" +#include <iostream> + +// for curl_getdate() (apparently parsing RFC 1123 dates is hard) +#include <curl/curl.h> + +LLPluginCookieStore::LLPluginCookieStore(): + mHasChangedCookies(false) +{ +} + + +LLPluginCookieStore::~LLPluginCookieStore() +{ + clearCookies(); +} + + +LLPluginCookieStore::Cookie::Cookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end): + mCookie(s, cookie_start, cookie_end - cookie_start), + mNameStart(0), mNameEnd(0), + mValueStart(0), mValueEnd(0), + mDomainStart(0), mDomainEnd(0), + mPathStart(0), mPathEnd(0), + mDead(false), mChanged(true) +{ +} + +LLPluginCookieStore::Cookie *LLPluginCookieStore::Cookie::createFromString(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, const std::string &host) +{ + Cookie *result = new Cookie(s, cookie_start, cookie_end); + + if(!result->parse(host)) + { + delete result; + result = NULL; + } + + return result; +} + +std::string LLPluginCookieStore::Cookie::getKey() const +{ + std::string result; + if(mDomainEnd > mDomainStart) + { + result += mCookie.substr(mDomainStart, mDomainEnd - mDomainStart); + } + result += ';'; + if(mPathEnd > mPathStart) + { + result += mCookie.substr(mPathStart, mPathEnd - mPathStart); + } + result += ';'; + result += mCookie.substr(mNameStart, mNameEnd - mNameStart); + return result; +} + +bool LLPluginCookieStore::Cookie::parse(const std::string &host) +{ + bool first_field = true; + + std::string::size_type cookie_end = mCookie.size(); + std::string::size_type field_start = 0; + + LL_DEBUGS("CookieStoreParse") << "parsing cookie: " << mCookie << LL_ENDL; + while(field_start < cookie_end) + { + // Finding the start of the next field requires honoring special quoting rules + // see the definition of 'quoted-string' in rfc2616 for details + std::string::size_type next_field_start = findFieldEnd(field_start); + + // The end of this field should not include the terminating ';' or any trailing whitespace + std::string::size_type field_end = mCookie.find_last_not_of("; ", next_field_start); + if(field_end == std::string::npos || field_end < field_start) + { + // This field was empty or all whitespace. Set end = start so it shows as empty. + field_end = field_start; + } + else if (field_end < next_field_start) + { + // we actually want the index of the char _after_ what 'last not of' found + ++field_end; + } + + // find the start of the actual name (skip separator and possible whitespace) + std::string::size_type name_start = mCookie.find_first_not_of("; ", field_start); + if(name_start == std::string::npos || name_start > next_field_start) + { + // Again, nothing but whitespace. + name_start = field_start; + } + + // the name and value are separated by the first equals sign + std::string::size_type name_value_sep = mCookie.find_first_of("=", name_start); + if(name_value_sep == std::string::npos || name_value_sep > field_end) + { + // No separator found, so this is a field without an = + name_value_sep = field_end; + } + + // the name end is before the name-value separator + std::string::size_type name_end = mCookie.find_last_not_of("= ", name_value_sep); + if(name_end == std::string::npos || name_end < name_start) + { + // I'm not sure how we'd hit this case... it seems like it would have to be an empty name. + name_end = name_start; + } + else if (name_end < name_value_sep) + { + // we actually want the index of the char _after_ what 'last not of' found + ++name_end; + } + + // Value is between the name-value sep and the end of the field. + std::string::size_type value_start = mCookie.find_first_not_of("= ", name_value_sep); + if(value_start == std::string::npos || value_start > field_end) + { + // All whitespace or empty value + value_start = field_end; + } + std::string::size_type value_end = mCookie.find_last_not_of("; ", field_end); + if(value_end == std::string::npos || value_end < value_start) + { + // All whitespace or empty value + value_end = value_start; + } + else if (value_end < field_end) + { + // we actually want the index of the char _after_ what 'last not of' found + ++value_end; + } + + LL_DEBUGS("CookieStoreParse") + << " field name: \"" << mCookie.substr(name_start, name_end - name_start) + << "\", value: \"" << mCookie.substr(value_start, value_end - value_start) << "\"" + << LL_ENDL; + + // See whether this field is one we know + if(first_field) + { + // The first field is the name=value pair + mNameStart = name_start; + mNameEnd = name_end; + mValueStart = value_start; + mValueEnd = value_end; + first_field = false; + } + else + { + // Subsequent fields must come from the set in rfc2109 + if(matchName(name_start, name_end, "expires")) + { + std::string date_string(mCookie, value_start, value_end - value_start); + // If the cookie contains an "expires" field, it MUST contain a parsable date. + + // HACK: LLDate apparently can't PARSE an rfc1123-format date, even though it can GENERATE one. + // The curl function curl_getdate can do this, but I'm hesitant to unilaterally introduce a curl dependency in LLDate. +#if 1 + time_t date = curl_getdate(date_string.c_str(), NULL ); + mDate.secondsSinceEpoch((F64)date); + LL_DEBUGS("CookieStoreParse") << " expire date parsed to: " << mDate.asRFC1123() << LL_ENDL; +#else + // This doesn't work (rfc1123-format dates cause it to fail) + if(!mDate.fromString(date_string)) + { + // Date failed to parse. + LL_WARNS("CookieStoreParse") << "failed to parse cookie's expire date: " << date << LL_ENDL; + return false; + } +#endif + } + else if(matchName(name_start, name_end, "domain")) + { + mDomainStart = value_start; + mDomainEnd = value_end; + } + else if(matchName(name_start, name_end, "path")) + { + mPathStart = value_start; + mPathEnd = value_end; + } + else if(matchName(name_start, name_end, "max-age")) + { + // TODO: how should we handle this? + } + else if(matchName(name_start, name_end, "secure")) + { + // We don't care about the value of this field (yet) + } + else if(matchName(name_start, name_end, "version")) + { + // We don't care about the value of this field (yet) + } + else if(matchName(name_start, name_end, "comment")) + { + // We don't care about the value of this field (yet) + } + else if(matchName(name_start, name_end, "httponly")) + { + // We don't care about the value of this field (yet) + } + else + { + // An unknown field is a parse failure + LL_WARNS("CookieStoreParse") << "unexpected field name: " << mCookie.substr(name_start, name_end - name_start) << LL_ENDL; + return false; + } + + } + + + // move on to the next field, skipping this field's separator and any leading whitespace + field_start = mCookie.find_first_not_of("; ", next_field_start); + } + + // The cookie MUST have a name + if(mNameEnd <= mNameStart) + return false; + + // If the cookie doesn't have a domain, add the current host as the domain. + if(mDomainEnd <= mDomainStart) + { + if(host.empty()) + { + // no domain and no current host -- this is a parse failure. + return false; + } + + // Figure out whether this cookie ended with a ";" or not... + std::string::size_type last_char = mCookie.find_last_not_of(" "); + if((last_char != std::string::npos) && (mCookie[last_char] != ';')) + { + mCookie += ";"; + } + + mCookie += " domain="; + mDomainStart = mCookie.size(); + mCookie += host; + mDomainEnd = mCookie.size(); + + LL_DEBUGS("CookieStoreParse") << "added domain (" << mDomainStart << " to " << mDomainEnd << "), new cookie is: " << mCookie << LL_ENDL; + } + + // If the cookie doesn't have a path, add "/". + if(mPathEnd <= mPathStart) + { + // Figure out whether this cookie ended with a ";" or not... + std::string::size_type last_char = mCookie.find_last_not_of(" "); + if((last_char != std::string::npos) && (mCookie[last_char] != ';')) + { + mCookie += ";"; + } + + mCookie += " path="; + mPathStart = mCookie.size(); + mCookie += "/"; + mPathEnd = mCookie.size(); + + LL_DEBUGS("CookieStoreParse") << "added path (" << mPathStart << " to " << mPathEnd << "), new cookie is: " << mCookie << LL_ENDL; + } + + + return true; +} + +std::string::size_type LLPluginCookieStore::Cookie::findFieldEnd(std::string::size_type start, std::string::size_type end) +{ + std::string::size_type result = start; + + if(end == std::string::npos) + end = mCookie.size(); + + bool in_quotes = false; + for(; (result < end); result++) + { + switch(mCookie[result]) + { + case '\\': + if(in_quotes) + result++; // The next character is backslash-quoted. Skip over it. + break; + case '"': + in_quotes = !in_quotes; + break; + case ';': + if(!in_quotes) + return result; + break; + } + } + + // If we got here, no ';' was found. + return end; +} + +bool LLPluginCookieStore::Cookie::matchName(std::string::size_type start, std::string::size_type end, const char *name) +{ + // NOTE: this assumes 'name' is already in lowercase. The code which uses it should be able to arrange this... + + while((start < end) && (*name != '\0')) + { + if(tolower(mCookie[start]) != *name) + return false; + + start++; + name++; + } + + // iff both strings hit the end at the same time, they're equal. + return ((start == end) && (*name == '\0')); +} + +std::string LLPluginCookieStore::getAllCookies() +{ + std::stringstream result; + writeAllCookies(result); + return result.str(); +} + +void LLPluginCookieStore::writeAllCookies(std::ostream& s) +{ + cookie_map_t::iterator iter; + for(iter = mCookies.begin(); iter != mCookies.end(); iter++) + { + // Don't return expired cookies + if(!iter->second->isDead()) + { + s << (iter->second->getCookie()) << "\n"; + } + } + +} + +std::string LLPluginCookieStore::getPersistentCookies() +{ + std::stringstream result; + writePersistentCookies(result); + return result.str(); +} + +void LLPluginCookieStore::writePersistentCookies(std::ostream& s) +{ + cookie_map_t::iterator iter; + for(iter = mCookies.begin(); iter != mCookies.end(); iter++) + { + // Don't return expired cookies or session cookies + if(!iter->second->isDead() && !iter->second->isSessionCookie()) + { + s << iter->second->getCookie() << "\n"; + } + } +} + +std::string LLPluginCookieStore::getChangedCookies(bool clear_changed) +{ + std::stringstream result; + writeChangedCookies(result, clear_changed); + + return result.str(); +} + +void LLPluginCookieStore::writeChangedCookies(std::ostream& s, bool clear_changed) +{ + if(mHasChangedCookies) + { + lldebugs << "returning changed cookies: " << llendl; + cookie_map_t::iterator iter; + for(iter = mCookies.begin(); iter != mCookies.end(); ) + { + cookie_map_t::iterator next = iter; + next++; + + // Only return cookies marked as "changed" + if(iter->second->isChanged()) + { + s << iter->second->getCookie() << "\n"; + + lldebugs << " " << iter->second->getCookie() << llendl; + + // If requested, clear the changed mark + if(clear_changed) + { + if(iter->second->isDead()) + { + // If this cookie was previously marked dead, it needs to be removed entirely. + delete iter->second; + mCookies.erase(iter); + } + else + { + // Not dead, just mark as not changed. + iter->second->setChanged(false); + } + } + } + + iter = next; + } + } + + if(clear_changed) + mHasChangedCookies = false; +} + +void LLPluginCookieStore::setAllCookies(const std::string &cookies, bool mark_changed) +{ + clearCookies(); + setCookies(cookies, mark_changed); +} + +void LLPluginCookieStore::readAllCookies(std::istream& s, bool mark_changed) +{ + clearCookies(); + readCookies(s, mark_changed); +} + +void LLPluginCookieStore::setCookies(const std::string &cookies, bool mark_changed) +{ + std::string::size_type start = 0; + + while(start != std::string::npos) + { + std::string::size_type end = cookies.find_first_of("\r\n", start); + if(end > start) + { + // The line is non-empty. Try to create a cookie from it. + setOneCookie(cookies, start, end, mark_changed); + } + start = cookies.find_first_not_of("\r\n ", end); + } +} + +void LLPluginCookieStore::setCookiesFromHost(const std::string &cookies, const std::string &host, bool mark_changed) +{ + std::string::size_type start = 0; + + while(start != std::string::npos) + { + std::string::size_type end = cookies.find_first_of("\r\n", start); + if(end > start) + { + // The line is non-empty. Try to create a cookie from it. + setOneCookie(cookies, start, end, mark_changed, host); + } + start = cookies.find_first_not_of("\r\n ", end); + } +} + +void LLPluginCookieStore::readCookies(std::istream& s, bool mark_changed) +{ + std::string line; + while(s.good() && !s.eof()) + { + std::getline(s, line); + if(!line.empty()) + { + // Try to create a cookie from this line. + setOneCookie(line, 0, std::string::npos, mark_changed); + } + } +} + +std::string LLPluginCookieStore::quoteString(const std::string &s) +{ + std::stringstream result; + + result << '"'; + + for(std::string::size_type i = 0; i < s.size(); ++i) + { + char c = s[i]; + switch(c) + { + // All these separators need to be quoted in HTTP headers, according to section 2.2 of rfc 2616: + case '(': case ')': case '<': case '>': case '@': + case ',': case ';': case ':': case '\\': case '"': + case '/': case '[': case ']': case '?': case '=': + case '{': case '}': case ' ': case '\t': + result << '\\'; + break; + } + + result << c; + } + + result << '"'; + + return result.str(); +} + +std::string LLPluginCookieStore::unquoteString(const std::string &s) +{ + std::stringstream result; + + bool in_quotes = false; + + for(std::string::size_type i = 0; i < s.size(); ++i) + { + char c = s[i]; + switch(c) + { + case '\\': + if(in_quotes) + { + // The next character is backslash-quoted. Pass it through untouched. + ++i; + if(i < s.size()) + { + result << s[i]; + } + continue; + } + break; + case '"': + in_quotes = !in_quotes; + continue; + break; + } + + result << c; + } + + return result.str(); +} + +// The flow for deleting a cookie is non-obvious enough that I should call it out here... +// Deleting a cookie is done by setting a cookie with the same name, path, and domain, but with an expire timestamp in the past. +// (This is exactly how a web server tells a browser to delete a cookie.) +// When deleting with mark_changed set to true, this replaces the existing cookie in the list with an entry that's marked both dead and changed. +// Some time later when writeChangedCookies() is called with clear_changed set to true, the dead cookie is deleted from the list after being returned, so that the +// delete operation (in the form of the expired cookie) is passed along. +void LLPluginCookieStore::setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed, const std::string &host) +{ + Cookie *cookie = Cookie::createFromString(s, cookie_start, cookie_end, host); + if(cookie) + { + LL_DEBUGS("CookieStoreUpdate") << "setting cookie: " << cookie->getCookie() << LL_ENDL; + + // Create a key for this cookie + std::string key = cookie->getKey(); + + // Check to see whether this cookie should have expired + if(!cookie->isSessionCookie() && (cookie->getDate() < LLDate::now())) + { + // This cookie has expired. + if(mark_changed) + { + // If we're marking cookies as changed, we should keep it anyway since we'll need to send it out with deltas. + cookie->setDead(true); + LL_DEBUGS("CookieStoreUpdate") << " marking dead" << LL_ENDL; + } + else + { + // If we're not marking cookies as changed, we don't need to keep this cookie at all. + // If the cookie was already in the list, delete it. + removeCookie(key); + + delete cookie; + cookie = NULL; + + LL_DEBUGS("CookieStoreUpdate") << " removing" << LL_ENDL; + } + } + + if(cookie) + { + // If it already exists in the map, replace it. + cookie_map_t::iterator iter = mCookies.find(key); + if(iter != mCookies.end()) + { + if(iter->second->getCookie() == cookie->getCookie()) + { + // The new cookie is identical to the old -- don't mark as changed. + // Just leave the old one in the map. + delete cookie; + cookie = NULL; + + LL_DEBUGS("CookieStoreUpdate") << " unchanged" << LL_ENDL; + } + else + { + // A matching cookie was already in the map. Replace it. + delete iter->second; + iter->second = cookie; + + cookie->setChanged(mark_changed); + if(mark_changed) + mHasChangedCookies = true; + + LL_DEBUGS("CookieStoreUpdate") << " replacing" << LL_ENDL; + } + } + else + { + // The cookie wasn't in the map. Insert it. + mCookies.insert(std::make_pair(key, cookie)); + + cookie->setChanged(mark_changed); + if(mark_changed) + mHasChangedCookies = true; + + LL_DEBUGS("CookieStoreUpdate") << " adding" << LL_ENDL; + } + } + } + else + { + LL_WARNS("CookieStoreUpdate") << "failed to parse cookie: " << s.substr(cookie_start, cookie_end - cookie_start) << LL_ENDL; + } + +} + +void LLPluginCookieStore::clearCookies() +{ + while(!mCookies.empty()) + { + cookie_map_t::iterator iter = mCookies.begin(); + delete iter->second; + mCookies.erase(iter); + } +} + +void LLPluginCookieStore::removeCookie(const std::string &key) +{ + cookie_map_t::iterator iter = mCookies.find(key); + if(iter != mCookies.end()) + { + delete iter->second; + mCookies.erase(iter); + } +} + diff --git a/linden/indra/llplugin/llplugincookiestore.h b/linden/indra/llplugin/llplugincookiestore.h new file mode 100644 index 000000000..69f0cf130 --- /dev/null +++ b/linden/indra/llplugin/llplugincookiestore.h @@ -0,0 +1,127 @@ +/** + * @file llplugincookiestore.h + * @brief LLPluginCookieStore provides central storage for http cookies used by plugins + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LL_LLPLUGINCOOKIESTORE_H +#define LL_LLPLUGINCOOKIESTORE_H + +#include "lldate.h" +#include <map> +#include <string> +#include <iostream> + +class LLPluginCookieStore +{ + LOG_CLASS(LLPluginCookieStore); +public: + LLPluginCookieStore(); + ~LLPluginCookieStore(); + + // gets all cookies currently in storage -- use when initializing a plugin + std::string getAllCookies(); + void writeAllCookies(std::ostream& s); + + // gets only persistent cookies (i.e. not session cookies) -- use when writing cookies to a file + std::string getPersistentCookies(); + void writePersistentCookies(std::ostream& s); + + // gets cookies which are marked as "changed" -- use when sending periodic updates to plugins + std::string getChangedCookies(bool clear_changed = true); + void writeChangedCookies(std::ostream& s, bool clear_changed = true); + + // (re)initializes internal data structures and bulk-sets cookies -- use when reading cookies from a file + void setAllCookies(const std::string &cookies, bool mark_changed = false); + void readAllCookies(std::istream& s, bool mark_changed = false); + + // sets one or more cookies (without reinitializing anything) -- use when receiving cookies from a plugin + void setCookies(const std::string &cookies, bool mark_changed = true); + void readCookies(std::istream& s, bool mark_changed = true); + + // sets one or more cookies (without reinitializing anything), supplying a hostname the cookies came from -- use when setting a cookie manually + void setCookiesFromHost(const std::string &cookies, const std::string &host, bool mark_changed = true); + + // quote or unquote a string as per the definition of 'quoted-string' in rfc2616 + static std::string quoteString(const std::string &s); + static std::string unquoteString(const std::string &s); + +private: + + void setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed, const std::string &host = LLStringUtil::null); + + class Cookie + { + public: + static Cookie *createFromString(const std::string &s, std::string::size_type cookie_start = 0, std::string::size_type cookie_end = std::string::npos, const std::string &host = LLStringUtil::null); + + // Construct a string from the cookie that uniquely represents it, to be used as a key in a std::map. + std::string getKey() const; + + const std::string &getCookie() const { return mCookie; }; + bool isSessionCookie() const { return mDate.isNull(); }; + + bool isDead() const { return mDead; }; + void setDead(bool dead) { mDead = dead; }; + + bool isChanged() const { return mChanged; }; + void setChanged(bool changed) { mChanged = changed; }; + + const LLDate &getDate() const { return mDate; }; + + private: + Cookie(const std::string &s, std::string::size_type cookie_start = 0, std::string::size_type cookie_end = std::string::npos); + bool parse(const std::string &host); + std::string::size_type findFieldEnd(std::string::size_type start = 0, std::string::size_type end = std::string::npos); + bool matchName(std::string::size_type start, std::string::size_type end, const char *name); + + std::string mCookie; // The full cookie, in RFC 2109 string format + LLDate mDate; // The expiration date of the cookie. For session cookies, this will be a null date (mDate.isNull() is true). + // Start/end indices of various parts of the cookie string. Stored as indices into the string to save space and time. + std::string::size_type mNameStart, mNameEnd; + std::string::size_type mValueStart, mValueEnd; + std::string::size_type mDomainStart, mDomainEnd; + std::string::size_type mPathStart, mPathEnd; + bool mDead; + bool mChanged; + }; + + typedef std::map<std::string, Cookie*> cookie_map_t; + + cookie_map_t mCookies; + bool mHasChangedCookies; + + void clearCookies(); + void removeCookie(const std::string &key); +}; + +#endif // LL_LLPLUGINCOOKIESTORE_H diff --git a/linden/indra/llplugin/llplugininstance.cpp b/linden/indra/llplugin/llplugininstance.cpp new file mode 100755 index 000000000..3a1395cd2 --- /dev/null +++ b/linden/indra/llplugin/llplugininstance.cpp @@ -0,0 +1,174 @@ +/** + * @file llplugininstance.cpp + * @brief LLPluginInstance handles loading the dynamic library of a plugin and setting up its entry points for message passing. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" + +#include "llplugininstance.h" +#include "aiaprpool.h" + +/** Virtual destructor. */ +LLPluginInstanceMessageListener::~LLPluginInstanceMessageListener() +{ +} + +/** + * TODO:DOC describe how it's used + */ +const char *LLPluginInstance::PLUGIN_INIT_FUNCTION_NAME = "LLPluginInitEntryPoint"; + +/** + * Constructor. + * + * @param[in] owner Plugin instance. TODO:DOC is this a good description of what "owner" is? + */ +LLPluginInstance::LLPluginInstance(LLPluginInstanceMessageListener *owner) : + mDSOHandle(NULL), + mPluginUserData(NULL), + mPluginSendMessageFunction(NULL) +{ + mOwner = owner; +} + +/** + * Destructor. + */ +LLPluginInstance::~LLPluginInstance() +{ + if(mDSOHandle != NULL) + { + apr_dso_unload(mDSOHandle); + mDSOHandle = NULL; + } +} + +/** + * Dynamically loads the plugin and runs the plugin's init function. + * + * @param[in] plugin_file Name of plugin dll/dylib/so. TODO:DOC is this correct? see .h + * @return 0 if successful, APR error code or error code from the plugin's init function on failure. + */ +int LLPluginInstance::load(std::string &plugin_file) +{ + pluginInitFunction init_function = NULL; + + int result = apr_dso_load(&mDSOHandle, + plugin_file.c_str(), + AIAPRRootPool::get()()); + if(result != APR_SUCCESS) + { + char buf[1024]; + apr_dso_error(mDSOHandle, buf, sizeof(buf)); + + LL_WARNS("Plugin") << "apr_dso_load of " << plugin_file << " failed with error " << result << " , additional info string: " << buf << LL_ENDL; + + } + + if(result == APR_SUCCESS) + { + result = apr_dso_sym((apr_dso_handle_sym_t*)&init_function, + mDSOHandle, + PLUGIN_INIT_FUNCTION_NAME); + + if(result != APR_SUCCESS) + { + LL_WARNS("Plugin") << "apr_dso_sym failed with error " << result << LL_ENDL; + } + } + + if(result == APR_SUCCESS) + { + result = init_function(staticReceiveMessage, (void*)this, &mPluginSendMessageFunction, &mPluginUserData); + + if(result != APR_SUCCESS) + { + LL_WARNS("Plugin") << "call to init function failed with error " << result << LL_ENDL; + } + } + + return (int)result; +} + +/** + * Sends a message to the plugin. + * + * @param[in] message Message + */ +void LLPluginInstance::sendMessage(const std::string &message) +{ + if(mPluginSendMessageFunction) + { + LL_DEBUGS("Plugin") << "sending message to plugin: \"" << message << "\"" << LL_ENDL; + mPluginSendMessageFunction(message.c_str(), &mPluginUserData); + } + else + { + LL_WARNS("Plugin") << "dropping message: \"" << message << "\"" << LL_ENDL; + } +} + +/** + * Idle. TODO:DOC what's the purpose of this? + * + */ +void LLPluginInstance::idle(void) +{ +} + +// static +void LLPluginInstance::staticReceiveMessage(const char *message_string, void **user_data) +{ + // TODO: validate that the user_data argument is still a valid LLPluginInstance pointer + // we could also use a key that's looked up in a map (instead of a direct pointer) for safety, but that's probably overkill + LLPluginInstance *self = (LLPluginInstance*)*user_data; + self->receiveMessage(message_string); +} + +/** + * Plugin receives message from plugin loader shell. + * + * @param[in] message_string Message + */ +void LLPluginInstance::receiveMessage(const char *message_string) +{ + if(mOwner) + { + LL_DEBUGS("Plugin") << "processing incoming message: \"" << message_string << "\"" << LL_ENDL; + mOwner->receivePluginMessage(message_string); + } + else + { + LL_WARNS("Plugin") << "dropping incoming message: \"" << message_string << "\"" << LL_ENDL; + } +} diff --git a/linden/indra/llplugin/llplugininstance.h b/linden/indra/llplugin/llplugininstance.h new file mode 100755 index 000000000..9cf6075ff --- /dev/null +++ b/linden/indra/llplugin/llplugininstance.h @@ -0,0 +1,106 @@ +/** + * @file llplugininstance.h + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LL_LLPLUGININSTANCE_H +#define LL_LLPLUGININSTANCE_H + +#include "llstring.h" +#include "llapr.h" + +#include "apr_dso.h" + +/** + * @brief LLPluginInstanceMessageListener receives messages sent from the plugin loader shell to the plugin. + */ +class LLPluginInstanceMessageListener +{ +public: + virtual ~LLPluginInstanceMessageListener(); + /** Plugin receives message from plugin loader shell. */ + virtual void receivePluginMessage(const std::string &message) = 0; +}; + +/** + * @brief LLPluginInstance handles loading the dynamic library of a plugin and setting up its entry points for message passing. + */ +class LLPluginInstance +{ + LOG_CLASS(LLPluginInstance); +public: + LLPluginInstance(LLPluginInstanceMessageListener *owner); + virtual ~LLPluginInstance(); + + // Load a plugin dll/dylib/so + // Returns 0 if successful, APR error code or error code returned from the plugin's init function on failure. + int load(std::string &plugin_file); + + // Sends a message to the plugin. + void sendMessage(const std::string &message); + + // TODO:DOC is this comment obsolete? can't find "send_count" anywhere in indra tree. + // send_count is the maximum number of message to process from the send queue. If negative, it will drain the queue completely. + // The receive queue is always drained completely. + // Returns the total number of messages processed from both queues. + void idle(void); + + /** The signature of the function for sending a message from plugin to plugin loader shell. + * + * @param[in] message_string Null-terminated C string + * @param[in] user_data The opaque reference that the callee supplied during setup. + */ + typedef void (*sendMessageFunction) (const char *message_string, void **user_data); + + /** The signature of the plugin init function. TODO:DOC check direction (pluging loader shell to plugin?) + * + * @param[in] host_user_data Data from plugin loader shell. + * @param[in] plugin_send_function Function for sending from the plugin loader shell to plugin. + */ + typedef int (*pluginInitFunction) (sendMessageFunction host_send_func, void *host_user_data, sendMessageFunction *plugin_send_func, void **plugin_user_data); + + /** Name of plugin init function */ + static const char *PLUGIN_INIT_FUNCTION_NAME; + +private: + static void staticReceiveMessage(const char *message_string, void **user_data); + void receiveMessage(const char *message_string); + + apr_dso_handle_t *mDSOHandle; + + void *mPluginUserData; + sendMessageFunction mPluginSendMessageFunction; + + LLPluginInstanceMessageListener *mOwner; +}; + +#endif // LL_LLPLUGININSTANCE_H diff --git a/linden/indra/llplugin/llpluginmessage.cpp b/linden/indra/llplugin/llpluginmessage.cpp new file mode 100755 index 000000000..6452f4afc --- /dev/null +++ b/linden/indra/llplugin/llpluginmessage.cpp @@ -0,0 +1,445 @@ +/** + * @file llpluginmessage.cpp + * @brief LLPluginMessage encapsulates the serialization/deserialization of messages passed to and from plugins. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" + +#include "llpluginmessage.h" +#include "llsdserialize.h" +#include "u64.h" + +/** + * Constructor. + */ +LLPluginMessage::LLPluginMessage() +{ +} + +/** + * Constructor. + * + * @param[in] p Existing message + */ +LLPluginMessage::LLPluginMessage(const LLPluginMessage &p) +{ + mMessage = p.mMessage; +} + +/** + * Constructor. + * + * @param[in] message_class Message class + * @param[in] message_name Message name + */ +LLPluginMessage::LLPluginMessage(const std::string &message_class, const std::string &message_name) +{ + setMessage(message_class, message_name); +} + + +/** + * Destructor. + */ +LLPluginMessage::~LLPluginMessage() +{ +} + +/** + * Reset all internal state. + */ +void LLPluginMessage::clear() +{ + mMessage = LLSD::emptyMap(); + mMessage["params"] = LLSD::emptyMap(); +} + +/** + * Sets the message class and name. Also has the side-effect of clearing any key-value pairs in the message. + * + * @param[in] message_class Message class + * @param[in] message_name Message name + */ +void LLPluginMessage::setMessage(const std::string &message_class, const std::string &message_name) +{ + clear(); + mMessage["class"] = message_class; + mMessage["name"] = message_name; +} + +/** + * Sets a key/value pair in the message, where the value is a string. + * + * @param[in] key Key + * @param[in] value String value + */ +void LLPluginMessage::setValue(const std::string &key, const std::string &value) +{ + mMessage["params"][key] = value; +} + +/** + * Sets a key/value pair in the message, where the value is LLSD. + * + * @param[in] key Key + * @param[in] value LLSD value + */ +void LLPluginMessage::setValueLLSD(const std::string &key, const LLSD &value) +{ + mMessage["params"][key] = value; +} + +/** + * Sets a key/value pair in the message, where the value is signed 32-bit. + * + * @param[in] key Key + * @param[in] value 32-bit signed value + */ +void LLPluginMessage::setValueS32(const std::string &key, S32 value) +{ + mMessage["params"][key] = value; +} + +/** + * Sets a key/value pair in the message, where the value is unsigned 32-bit. The value is stored as a string beginning with "0x". + * + * @param[in] key Key + * @param[in] value 32-bit unsigned value + */ +void LLPluginMessage::setValueU32(const std::string &key, U32 value) +{ + std::stringstream temp; + temp << "0x" << std::hex << value; + setValue(key, temp.str()); +} + +/** + * Sets a key/value pair in the message, where the value is a bool. + * + * @param[in] key Key + * @param[in] value Boolean value + */ +void LLPluginMessage::setValueBoolean(const std::string &key, bool value) +{ + mMessage["params"][key] = value; +} + +/** + * Sets a key/value pair in the message, where the value is a double. + * + * @param[in] key Key + * @param[in] value Boolean value + */ +void LLPluginMessage::setValueReal(const std::string &key, F64 value) +{ + mMessage["params"][key] = value; +} + +/** + * Sets a key/value pair in the message, where the value is a pointer. The pointer is stored as a string. + * + * @param[in] key Key + * @param[in] value Pointer value + */ +void LLPluginMessage::setValuePointer(const std::string &key, void* value) +{ + std::stringstream temp; + // iostreams should output pointer values in hex with an initial 0x by default. + temp << value; + setValue(key, temp.str()); +} + +/** + * Gets the message class. + * + * @return Message class + */ +std::string LLPluginMessage::getClass(void) const +{ + return mMessage["class"]; +} + +/** + * Gets the message name. + * + * @return Message name + */ +std::string LLPluginMessage::getName(void) const +{ + return mMessage["name"]; +} + +/** + * Returns true if the specified key exists in this message (useful for optional parameters). + * + * @param[in] key Key + * + * @return True if key exists, false otherwise. + */ +bool LLPluginMessage::hasValue(const std::string &key) const +{ + bool result = false; + + if(mMessage["params"].has(key)) + { + result = true; + } + + return result; +} + +/** + * Gets the value of a key as a string. If the key does not exist, an empty string will be returned. + * + * @param[in] key Key + * + * @return String value of key if key exists, empty string if key does not exist. + */ +std::string LLPluginMessage::getValue(const std::string &key) const +{ + std::string result; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asString(); + } + + return result; +} + +/** + * Gets the value of a key as LLSD. If the key does not exist, a null LLSD will be returned. + * + * @param[in] key Key + * + * @return LLSD value of key if key exists, null LLSD if key does not exist. + */ +LLSD LLPluginMessage::getValueLLSD(const std::string &key) const +{ + LLSD result; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key]; + } + + return result; +} + +/** + * Gets the value of a key as signed 32-bit int. If the key does not exist, 0 will be returned. + * + * @param[in] key Key + * + * @return Signed 32-bit int value of key if key exists, 0 if key does not exist. + */ +S32 LLPluginMessage::getValueS32(const std::string &key) const +{ + S32 result = 0; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asInteger(); + } + + return result; +} + +/** + * Gets the value of a key as unsigned 32-bit int. If the key does not exist, 0 will be returned. + * + * @param[in] key Key + * + * @return Unsigned 32-bit int value of key if key exists, 0 if key does not exist. + */ +U32 LLPluginMessage::getValueU32(const std::string &key) const +{ + U32 result = 0; + + if(mMessage["params"].has(key)) + { + std::string value = mMessage["params"][key].asString(); + + result = (U32)strtoul(value.c_str(), NULL, 16); + } + + return result; +} + +/** + * Gets the value of a key as a bool. If the key does not exist, false will be returned. + * + * @param[in] key Key + * + * @return Boolean value of key if it exists, false otherwise. + */ +bool LLPluginMessage::getValueBoolean(const std::string &key) const +{ + bool result = false; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asBoolean(); + } + + return result; +} + +/** + * Gets the value of a key as a double. If the key does not exist, 0 will be returned. + * + * @param[in] key Key + * + * @return Value as a double if key exists, 0 otherwise. + */ +F64 LLPluginMessage::getValueReal(const std::string &key) const +{ + F64 result = 0.0f; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asReal(); + } + + return result; +} + +/** + * Gets the value of a key as a pointer. If the key does not exist, NULL will be returned. + * + * @param[in] key Key + * + * @return Pointer value if key exists, NULL otherwise. + */ +void* LLPluginMessage::getValuePointer(const std::string &key) const +{ + void* result = NULL; + + if(mMessage["params"].has(key)) + { + std::string value = mMessage["params"][key].asString(); + + result = (void*)llstrtou64(value.c_str(), NULL, 16); + } + + return result; +} + +/** + * Flatten the message into a string. + * + * @return Message as a string. + */ +std::string LLPluginMessage::generate(void) const +{ + std::ostringstream result; + + // Pretty XML may be slightly easier to deal with while debugging... +// LLSDSerialize::toXML(mMessage, result); + LLSDSerialize::toPrettyXML(mMessage, result); + + return result.str(); +} + +/** + * Parse an incoming message into component parts. Clears all existing state before starting the parse. + * + * @return Returns -1 on failure, otherwise returns the number of key/value pairs in the incoming message. + */ +int LLPluginMessage::parse(const std::string &message) +{ + // clear any previous state + clear(); + + std::istringstream input(message); + + S32 parse_result = LLSDSerialize::fromXML(mMessage, input); + + return (int)parse_result; +} + + +/** + * Destructor + */ +LLPluginMessageListener::~LLPluginMessageListener() +{ + // TODO: should listeners have a way to ensure they're removed from dispatcher lists when deleted? +} + + +/** + * Destructor + */ +LLPluginMessageDispatcher::~LLPluginMessageDispatcher() +{ + +} + +/** + * Add a message listener. TODO:DOC need more info on what uses this. when are multiple listeners needed? + * + * @param[in] listener Message listener + */ +void LLPluginMessageDispatcher::addPluginMessageListener(LLPluginMessageListener *listener) +{ + mListeners.insert(listener); +} + +/** + * Remove a message listener. + * + * @param[in] listener Message listener + */ +void LLPluginMessageDispatcher::removePluginMessageListener(LLPluginMessageListener *listener) +{ + mListeners.erase(listener); +} + +/** + * Distribute a message to all message listeners. + * + * @param[in] message Message + */ +void LLPluginMessageDispatcher::dispatchPluginMessage(const LLPluginMessage &message) +{ + for (listener_set_t::iterator it = mListeners.begin(); + it != mListeners.end(); + ) + { + LLPluginMessageListener* listener = *it; + listener->receivePluginMessage(message); + // In case something deleted an entry. + it = mListeners.upper_bound(listener); + } +} diff --git a/linden/indra/llplugin/llpluginmessage.h b/linden/indra/llplugin/llpluginmessage.h new file mode 100755 index 000000000..fe504c8b9 --- /dev/null +++ b/linden/indra/llplugin/llpluginmessage.h @@ -0,0 +1,144 @@ +/** + * @file llpluginmessage.h + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LL_LLPLUGINMESSAGE_H +#define LL_LLPLUGINMESSAGE_H + +#include "llsd.h" + +/** + * @brief LLPluginMessage encapsulates the serialization/deserialization of messages passed to and from plugins. + */ +class LLPluginMessage +{ + LOG_CLASS(LLPluginMessage); +public: + LLPluginMessage(); + LLPluginMessage(const LLPluginMessage &p); + LLPluginMessage(const std::string &message_class, const std::string &message_name); + ~LLPluginMessage(); + + // reset all internal state + void clear(void); + + // Sets the message class and name + // Also has the side-effect of clearing any key/value pairs in the message. + void setMessage(const std::string &message_class, const std::string &message_name); + + // Sets a key/value pair in the message + void setValue(const std::string &key, const std::string &value); + void setValueLLSD(const std::string &key, const LLSD &value); + void setValueS32(const std::string &key, S32 value); + void setValueU32(const std::string &key, U32 value); + void setValueBoolean(const std::string &key, bool value); + void setValueReal(const std::string &key, F64 value); + void setValuePointer(const std::string &key, void *value); + + std::string getClass(void) const; + std::string getName(void) const; + + // Returns true if the specified key exists in this message (useful for optional parameters) + bool hasValue(const std::string &key) const; + + // get the value of a particular key as a string. If the key doesn't exist in the message, an empty string will be returned. + std::string getValue(const std::string &key) const; + + // get the value of a particular key as LLSD. If the key doesn't exist in the message, a null LLSD will be returned. + LLSD getValueLLSD(const std::string &key) const; + + // get the value of a key as a S32. If the value wasn't set as a S32, behavior is undefined. + S32 getValueS32(const std::string &key) const; + + // get the value of a key as a U32. Since there isn't an LLSD type for this, we use a hexadecimal string instead. + U32 getValueU32(const std::string &key) const; + + // get the value of a key as a Boolean. + bool getValueBoolean(const std::string &key) const; + + // get the value of a key as a float. + F64 getValueReal(const std::string &key) const; + + // get the value of a key as a pointer. + void* getValuePointer(const std::string &key) const; + + // Flatten the message into a string + std::string generate(void) const; + + // Parse an incoming message into component parts + // (this clears out all existing state before starting the parse) + // Returns -1 on failure, otherwise returns the number of key/value pairs in the message. + int parse(const std::string &message); + + +private: + + LLSD mMessage; + +}; + +/** + * @brief Listener for plugin messages. + */ +class LLPluginMessageListener +{ +public: + virtual ~LLPluginMessageListener(); + /** Plugin receives message from plugin loader shell. */ + virtual void receivePluginMessage(const LLPluginMessage &message) = 0; + +}; + +/** + * @brief Dispatcher for plugin messages. + * + * Manages the set of plugin message listeners and distributes messages to plugin message listeners. + */ +class LLPluginMessageDispatcher +{ +public: + virtual ~LLPluginMessageDispatcher(); + + void addPluginMessageListener(LLPluginMessageListener *); + void removePluginMessageListener(LLPluginMessageListener *); +protected: + void dispatchPluginMessage(const LLPluginMessage &message); + + /** A set of message listeners. */ + typedef std::set<LLPluginMessageListener*> listener_set_t; + /** The set of message listeners. */ + listener_set_t mListeners; +}; + + +#endif // LL_LLPLUGINMESSAGE_H diff --git a/linden/indra/llplugin/llpluginmessageclasses.h b/linden/indra/llplugin/llpluginmessageclasses.h new file mode 100755 index 000000000..8812a1676 --- /dev/null +++ b/linden/indra/llplugin/llpluginmessageclasses.h @@ -0,0 +1,60 @@ +/** + * @file llpluginmessageclasses.h + * @brief This file defines the versions of existing message classes for LLPluginMessage. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LL_LLPLUGINMESSAGECLASSES_H +#define LL_LLPLUGINMESSAGECLASSES_H + +// Version strings for each plugin message class. +// Backwards-compatible changes (i.e. changes which only add new messges) should increment the minor version (i.e. "1.0" -> "1.1"). +// Non-backwards-compatible changes (which delete messages or change their semantics) should increment the major version (i.e. "1.1" -> "2.0"). +// Plugins will supply the set of message classes they understand, with version numbers, as part of their init_response message. +// The contents and semantics of the base:init message must NEVER change in a non-backwards-compatible way, as a special case. + +#define LLPLUGIN_MESSAGE_CLASS_INTERNAL "internal" +#define LLPLUGIN_MESSAGE_CLASS_INTERNAL_VERSION "1.0" + +#define LLPLUGIN_MESSAGE_CLASS_BASE "base" +#define LLPLUGIN_MESSAGE_CLASS_BASE_VERSION "1.0" + +#define LLPLUGIN_MESSAGE_CLASS_MEDIA "media" +#define LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION "1.0" + +#define LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER "media_browser" +#define LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION "1.0" + +#define LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME "media_time" +#define LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION "1.0" + +#endif // LL_LLPLUGINMESSAGECLASSES_H diff --git a/linden/indra/llplugin/llpluginmessagepipe.cpp b/linden/indra/llplugin/llpluginmessagepipe.cpp new file mode 100755 index 000000000..ebac3c52b --- /dev/null +++ b/linden/indra/llplugin/llpluginmessagepipe.cpp @@ -0,0 +1,385 @@ +/** + * @file llpluginmessagepipe.cpp + * @brief Classes that implement connections from the plugin system to pipes/pumps. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" + +#include "llpluginmessagepipe.h" +#include "llbufferstream.h" + +#include "llapr.h" + +static const char MESSAGE_DELIMITER = '\0'; + +LLPluginMessagePipeOwner::LLPluginMessagePipeOwner() : + mMessagePipe(NULL), + mSocketError(APR_SUCCESS) +{ +} + +// virtual +LLPluginMessagePipeOwner::~LLPluginMessagePipeOwner() +{ + killMessagePipe(); +} + +// virtual +apr_status_t LLPluginMessagePipeOwner::socketError(apr_status_t error) +{ + mSocketError = error; + return error; +}; + +//virtual +void LLPluginMessagePipeOwner::setMessagePipe(LLPluginMessagePipe *read_pipe) +{ + // Save a reference to this pipe + mMessagePipe = read_pipe; +} + +bool LLPluginMessagePipeOwner::canSendMessage(void) +{ + return (mMessagePipe != NULL); +} + +bool LLPluginMessagePipeOwner::writeMessageRaw(const std::string &message) +{ + bool result = true; + if(mMessagePipe != NULL) + { + result = mMessagePipe->addMessage(message); + } + else + { + LL_WARNS("Plugin") << "dropping message: " << message << LL_ENDL; + result = false; + } + + return result; +} + +void LLPluginMessagePipeOwner::killMessagePipe(void) +{ + if(mMessagePipe != NULL) + { + delete mMessagePipe; + mMessagePipe = NULL; + } +} + +LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket): + mOwner(owner), + mSocket(socket) +{ + + mOwner->setMessagePipe(this); +} + +LLPluginMessagePipe::~LLPluginMessagePipe() +{ + if(mOwner != NULL) + { + mOwner->setMessagePipe(NULL); + } +} + +bool LLPluginMessagePipe::addMessage(const std::string &message) +{ + // queue the message for later output + LLMutexLock lock(&mOutputMutex); + mOutput += message; + mOutput += MESSAGE_DELIMITER; // message separator + + return true; +} + +void LLPluginMessagePipe::clearOwner(void) +{ + // The owner is done with this pipe. The next call to process_impl should send any remaining data and exit. + mOwner = NULL; +} + +void LLPluginMessagePipe::setSocketTimeout(apr_interval_time_t timeout_usec) +{ + // We never want to sleep forever, so force negative timeouts to become non-blocking. + + // according to this page: http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html + // blocking/non-blocking with apr sockets is somewhat non-portable. + + if(timeout_usec <= 0) + { + // Make the socket non-blocking + apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); + apr_socket_timeout_set(mSocket->getSocket(), 0); + } + else + { + // Make the socket blocking-with-timeout + apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); + apr_socket_timeout_set(mSocket->getSocket(), timeout_usec); + } +} + +bool LLPluginMessagePipe::pump(F64 timeout) +{ + bool result = pumpOutput(); + + if(result) + { + result = pumpInput(timeout); + } + + return result; +} + +bool LLPluginMessagePipe::pumpOutput() +{ + bool result = true; + + if(mSocket) + { + apr_status_t status; + apr_size_t size; + + LLMutexLock lock(&mOutputMutex); + if(!mOutput.empty()) + { + // write any outgoing messages + size = (apr_size_t)mOutput.size(); + + setSocketTimeout(0); + +// LL_INFOS("Plugin") << "before apr_socket_send, size = " << size << LL_ENDL; + + status = apr_socket_send( + mSocket->getSocket(), + (const char*)mOutput.data(), + &size); + +// LL_INFOS("Plugin") << "after apr_socket_send, size = " << size << LL_ENDL; + + if(status == APR_SUCCESS) + { + // success + mOutput = mOutput.substr(size); + } + else if(APR_STATUS_IS_EAGAIN(status)) + { + // Socket buffer is full... + // remove the written part from the buffer and try again later. + mOutput = mOutput.substr(size); + } + else if(APR_STATUS_IS_EOF(status)) + { + // This is what we normally expect when a plugin exits. + llinfos << "Got EOF from plugin socket. " << llendl; + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + } + else + { + // some other error + // Treat this as fatal. + ll_apr_warn_status(status); + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + } + } + } + + return result; +} + +bool LLPluginMessagePipe::pumpInput(F64 timeout) +{ + bool result = true; + + if(mSocket) + { + apr_status_t status; + apr_size_t size; + + // FIXME: For some reason, the apr timeout stuff isn't working properly on windows. + // Until such time as we figure out why, don't try to use the socket timeout -- just sleep here instead. +#if LL_WINDOWS + if(result) + { + if(timeout != 0.0f) + { + ms_sleep((int)(timeout * 1000.0f)); + timeout = 0.0f; + } + } +#endif + + // Check for incoming messages + if(result) + { + char input_buf[1024]; + apr_size_t request_size; + + if(timeout == 0.0f) + { + // If we have no timeout, start out with a full read. + request_size = sizeof(input_buf); + } + else + { + // Start out by reading one byte, so that any data received will wake us up. + request_size = 1; + } + + // and use the timeout so we'll sleep if no data is available. + setSocketTimeout((apr_interval_time_t)(timeout * 1000000)); + + while(1) + { + size = request_size; + +// LL_INFOS("Plugin") << "before apr_socket_recv, size = " << size << LL_ENDL; + + status = apr_socket_recv( + mSocket->getSocket(), + input_buf, + &size); + +// LL_INFOS("Plugin") << "after apr_socket_recv, size = " << size << LL_ENDL; + + if(size > 0) + { + LLMutexLock lock(&mInputMutex); + mInput.append(input_buf, size); + } + + if(status == APR_SUCCESS) + { + LL_DEBUGS("PluginSocket") << "success, read " << size << LL_ENDL; + + if(size != request_size) + { + // This was a short read, so we're done. + break; + } + } + else if(APR_STATUS_IS_TIMEUP(status)) + { + LL_DEBUGS("PluginSocket") << "TIMEUP, read " << size << LL_ENDL; + + // Timeout was hit. Since the initial read is 1 byte, this should never be a partial read. + break; + } + else if(APR_STATUS_IS_EAGAIN(status)) + { + LL_DEBUGS("PluginSocket") << "EAGAIN, read " << size << LL_ENDL; + + // Non-blocking read returned immediately. + break; + } + else if(APR_STATUS_IS_EOF(status)) + { + // This is what we normally expect when a plugin exits. + LL_INFOS("PluginSocket") << "Got EOF from plugin socket. " << LL_ENDL; + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + break; + } + else + { + // some other error + // Treat this as fatal. + ll_apr_warn_status(status); + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + break; + } + + if(timeout != 0.0f) + { + // Second and subsequent reads should not use the timeout + setSocketTimeout(0); + // and should try to fill the input buffer + request_size = sizeof(input_buf); + } + } + + processInput(); + } + } + + return result; +} + +void LLPluginMessagePipe::processInput(void) +{ + // Look for input delimiter(s) in the input buffer. + int delim; + mInputMutex.lock(); + while((delim = mInput.find(MESSAGE_DELIMITER)) != std::string::npos) + { + // Let the owner process this message + if (mOwner) + { + // Pull the message out of the input buffer before calling receiveMessageRaw. + // It's now possible for this function to get called recursively (in the case where the plugin makes a blocking request) + // and this guarantees that the messages will get dequeued correctly. + std::string message(mInput, 0, delim); + mInput.erase(0, delim + 1); + mInputMutex.unlock(); + mOwner->receiveMessageRaw(message); + mInputMutex.lock(); + } + else + { + LL_WARNS("Plugin") << "!mOwner" << LL_ENDL; + } + } + mInputMutex.unlock(); +} + diff --git a/linden/indra/llplugin/llpluginmessagepipe.h b/linden/indra/llplugin/llpluginmessagepipe.h new file mode 100755 index 000000000..6eedca27f --- /dev/null +++ b/linden/indra/llplugin/llpluginmessagepipe.h @@ -0,0 +1,100 @@ +/** + * @file llpluginmessagepipe.h + * @brief Classes that implement connections from the plugin system to pipes/pumps. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LL_LLPLUGINMESSAGEPIPE_H +#define LL_LLPLUGINMESSAGEPIPE_H + +#include "lliosocket.h" +#include "llthread.h" + +class LLPluginMessagePipe; + +// Inherit from this to be able to receive messages from the LLPluginMessagePipe +class LLPluginMessagePipeOwner +{ + LOG_CLASS(LLPluginMessagePipeOwner); +public: + LLPluginMessagePipeOwner(); + virtual ~LLPluginMessagePipeOwner(); + // called with incoming messages + virtual void receiveMessageRaw(const std::string &message) = 0; + // called when the socket has an error + virtual apr_status_t socketError(apr_status_t error); + + // called from LLPluginMessagePipe to manage the connection with LLPluginMessagePipeOwner -- do not use! + virtual void setMessagePipe(LLPluginMessagePipe *message_pipe); + +protected: + // returns false if writeMessageRaw() would drop the message + bool canSendMessage(void); + // call this to send a message over the pipe + bool writeMessageRaw(const std::string &message); + // call this to close the pipe + void killMessagePipe(void); + + LLPluginMessagePipe *mMessagePipe; + apr_status_t mSocketError; +}; + +class LLPluginMessagePipe +{ + LOG_CLASS(LLPluginMessagePipe); +public: + LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket); + virtual ~LLPluginMessagePipe(); + + bool addMessage(const std::string &message); + void clearOwner(void); + + bool pump(F64 timeout = 0.0f); + bool pumpOutput(); + bool pumpInput(F64 timeout = 0.0f); + +protected: + void processInput(void); + + // used internally by pump() + void setSocketTimeout(apr_interval_time_t timeout_usec); + + LLMutex mInputMutex; + std::string mInput; + LLMutex mOutputMutex; + std::string mOutput; + + LLPluginMessagePipeOwner *mOwner; + LLSocket::ptr_t mSocket; +}; + +#endif // LL_LLPLUGINMESSAGE_H diff --git a/linden/indra/llplugin/llpluginprocesschild.cpp b/linden/indra/llplugin/llpluginprocesschild.cpp new file mode 100755 index 000000000..d2238236f --- /dev/null +++ b/linden/indra/llplugin/llpluginprocesschild.cpp @@ -0,0 +1,569 @@ +/** + * @file llpluginprocesschild.cpp + * @brief LLPluginProcessChild handles the child side of the external-process plugin API. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" + +#include "llpluginprocesschild.h" +#include "llplugininstance.h" +#include "llpluginmessagepipe.h" +#include "llpluginmessageclasses.h" + +static const F32 HEARTBEAT_SECONDS = 1.0f; +static const F32 PLUGIN_IDLE_SECONDS = 1.0f / 100.0f; // Each call to idle will give the plugin this much time. + +LLPluginProcessChild::LLPluginProcessChild() +{ + mState = STATE_UNINITIALIZED; + mInstance = NULL; + mSocket = LLSocket::create(LLSocket::STREAM_TCP); + mSleepTime = PLUGIN_IDLE_SECONDS; // default: send idle messages at 100Hz + mCPUElapsed = 0.0f; + mBlockingRequest = false; + mBlockingResponseReceived = false; +} + +LLPluginProcessChild::~LLPluginProcessChild() +{ + if(mInstance != NULL) + { + sendMessageToPlugin(LLPluginMessage("base", "cleanup")); + + // IMPORTANT: under some (unknown) circumstances the apr_dso_unload() triggered when mInstance is deleted + // appears to fail and lock up which means that a given instance of the slplugin process never exits. + // This is bad, especially when users try to update their version of SL - it fails because the slplugin + // process as well as a bunch of plugin specific files are locked and cannot be overwritten. + exit( 0 ); + //delete mInstance; + //mInstance = NULL; + } +} + +void LLPluginProcessChild::killSockets(void) +{ + killMessagePipe(); + mSocket.reset(); +} + +void LLPluginProcessChild::init(U32 launcher_port) +{ + mLauncherHost = LLHost("127.0.0.1", launcher_port); + setState(STATE_INITIALIZED); +} + +void LLPluginProcessChild::idle(void) +{ + bool idle_again; + do + { + if(APR_STATUS_IS_EOF(mSocketError)) + { + // Plugin socket was closed. This covers both normal plugin termination and host crashes. + setState(STATE_ERROR); + } + else if(mSocketError != APR_SUCCESS) + { + LL_INFOS("Plugin") << "message pipe is in error state (" << mSocketError << "), moving to STATE_ERROR"<< LL_ENDL; + setState(STATE_ERROR); + } + + if((mState > STATE_INITIALIZED) && (mMessagePipe == NULL)) + { + // The pipe has been closed -- we're done. + // TODO: This could be slightly more subtle, but I'm not sure it needs to be. + LL_INFOS("Plugin") << "message pipe went away, moving to STATE_ERROR"<< LL_ENDL; + setState(STATE_ERROR); + } + + // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState(). + // USE THIS CAREFULLY, since it can starve other code. Specifically make sure there's no way to get into a closed cycle and never return. + // When in doubt, don't do it. + idle_again = false; + + if(mInstance != NULL) + { + // Provide some time to the plugin + mInstance->idle(); + } + + switch(mState) + { + case STATE_UNINITIALIZED: + break; + + case STATE_INITIALIZED: + if(mSocket->blockingConnect(mLauncherHost)) + { + // This automatically sets mMessagePipe + new LLPluginMessagePipe(this, mSocket); + + setState(STATE_CONNECTED); + } + else + { + // connect failed + setState(STATE_ERROR); + } + break; + + case STATE_CONNECTED: + sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hello")); + setState(STATE_PLUGIN_LOADING); + break; + + case STATE_PLUGIN_LOADING: + if(!mPluginFile.empty()) + { + mInstance = new LLPluginInstance(this); + if(mInstance->load(mPluginFile) == 0) + { + mHeartbeat.start(); + mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); + mCPUElapsed = 0.0f; + setState(STATE_PLUGIN_LOADED); + } + else + { + setState(STATE_ERROR); + } + } + break; + + case STATE_PLUGIN_LOADED: + { + setState(STATE_PLUGIN_INITIALIZING); + LLPluginMessage message("base", "init"); + sendMessageToPlugin(message); + } + break; + + case STATE_PLUGIN_INITIALIZING: + // waiting for init_response... + break; + + case STATE_RUNNING: + if(mInstance != NULL) + { + // Provide some time to the plugin + LLPluginMessage message("base", "idle"); + message.setValueReal("time", PLUGIN_IDLE_SECONDS); + sendMessageToPlugin(message); + + mInstance->idle(); + + if(mHeartbeat.hasExpired()) + { + + // This just proves that we're not stuck down inside the plugin code. + LLPluginMessage heartbeat(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat"); + + // Calculate the approximage CPU usage fraction (floating point value between 0 and 1) used by the plugin this heartbeat cycle. + // Note that this will not take into account any threads or additional processes the plugin spawns, but it's a first approximation. + // If we could write OS-specific functions to query the actual CPU usage of this process, that would be a better approximation. + heartbeat.setValueReal("cpu_usage", mCPUElapsed / mHeartbeat.getElapsedTimeF64()); + + sendMessageToParent(heartbeat); + + mHeartbeat.reset(); + mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); + mCPUElapsed = 0.0f; + } + } + // receivePluginMessage will transition to STATE_UNLOADING + break; + + case STATE_UNLOADING: + if(mInstance != NULL) + { + sendMessageToPlugin(LLPluginMessage("base", "cleanup")); + delete mInstance; + mInstance = NULL; + } + setState(STATE_UNLOADED); + break; + + case STATE_UNLOADED: + killSockets(); + setState(STATE_DONE); + break; + + case STATE_ERROR: + // Close the socket to the launcher + killSockets(); + // TODO: Where do we go from here? Just exit()? + setState(STATE_DONE); + break; + + case STATE_DONE: + // just sit here. + break; + } + + } while (idle_again); +} + +void LLPluginProcessChild::sleep(F64 seconds) +{ + deliverQueuedMessages(); + if(mMessagePipe) + { + mMessagePipe->pump(seconds); + } + else + { + ms_sleep((int)(seconds * 1000.0f)); + } +} + +void LLPluginProcessChild::pump(void) +{ + deliverQueuedMessages(); + if(mMessagePipe) + { + mMessagePipe->pump(0.0f); + } + else + { + // Should we warn here? + } +} + + +bool LLPluginProcessChild::isRunning(void) +{ + bool result = false; + + if(mState == STATE_RUNNING) + result = true; + + return result; +} + +bool LLPluginProcessChild::isDone(void) +{ + bool result = false; + + switch(mState) + { + case STATE_DONE: + result = true; + break; + default: + break; + } + + return result; +} + +void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) +{ + if (mInstance) + { + std::string buffer = message.generate(); + + LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL; + LLTimer elapsed; + + mInstance->sendMessage(buffer); + + mCPUElapsed += elapsed.getElapsedTimeF64(); + } + else + { + LL_WARNS("Plugin") << "mInstance == NULL" << LL_ENDL; + } +} + +void LLPluginProcessChild::sendMessageToParent(const LLPluginMessage &message) +{ + std::string buffer = message.generate(); + + LL_DEBUGS("Plugin") << "Sending to parent: " << buffer << LL_ENDL; + + writeMessageRaw(buffer); +} + +void LLPluginProcessChild::receiveMessageRaw(const std::string &message) +{ + // Incoming message from the TCP Socket + + LL_DEBUGS("Plugin") << "Received from parent: " << message << LL_ENDL; + + // Decode this message + LLPluginMessage parsed; + parsed.parse(message); + + if(mBlockingRequest) + { + // We're blocking the plugin waiting for a response. + + if(parsed.hasValue("blocking_response")) + { + // This is the message we've been waiting for -- fall through and send it immediately. + mBlockingResponseReceived = true; + } + else + { + // Still waiting. Queue this message and don't process it yet. + mMessageQueue.push(message); + return; + } + } + + bool passMessage = true; + + // FIXME: how should we handle queueing here? + + { + std::string message_class = parsed.getClass(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) + { + passMessage = false; + + std::string message_name = parsed.getName(); + if(message_name == "load_plugin") + { + mPluginFile = parsed.getValue("file"); + } + else if(message_name == "shm_add") + { + std::string name = parsed.getValue("name"); + size_t size = (size_t)parsed.getValueS32("size"); + + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + // Need to remove the old region first + LL_WARNS("Plugin") << "Adding a duplicate shared memory segment!" << LL_ENDL; + } + else + { + // This is a new region + LLPluginSharedMemory *region = new LLPluginSharedMemory; + if(region->attach(name, size)) + { + mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region)); + + std::stringstream addr; + addr << region->getMappedAddress(); + + // Send the add notification to the plugin + LLPluginMessage message("base", "shm_added"); + message.setValue("name", name); + message.setValueS32("size", (S32)size); + message.setValuePointer("address", region->getMappedAddress()); + sendMessageToPlugin(message); + + // and send the response to the parent + message.setMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add_response"); + message.setValue("name", name); + sendMessageToParent(message); + } + else + { + LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL; + delete region; + } + } + + } + else if(message_name == "shm_remove") + { + std::string name = parsed.getValue("name"); + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + // forward the remove request to the plugin -- its response will trigger us to detach the segment. + LLPluginMessage message("base", "shm_remove"); + message.setValue("name", name); + sendMessageToPlugin(message); + } + else + { + LL_WARNS("Plugin") << "shm_remove for unknown memory segment!" << LL_ENDL; + } + } + else if(message_name == "sleep_time") + { + mSleepTime = parsed.getValueReal("time"); + } + else if(message_name == "crash") + { + // Crash the plugin + LL_ERRS("Plugin") << "Plugin crash requested." << LL_ENDL; + } + else if(message_name == "hang") + { + // Hang the plugin + LL_WARNS("Plugin") << "Plugin hang requested." << LL_ENDL; + while(1) + { + // wheeeeeeeee...... + } + } + else + { + LL_WARNS("Plugin") << "Unknown internal message from parent: " << message_name << LL_ENDL; + } + } + } + + if(passMessage && mInstance != NULL) + { + LLTimer elapsed; + + mInstance->sendMessage(message); + + mCPUElapsed += elapsed.getElapsedTimeF64(); + } +} + +/* virtual */ +void LLPluginProcessChild::receivePluginMessage(const std::string &message) +{ + LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL; + + if(mBlockingRequest) + { + // + LL_ERRS("Plugin") << "Can't send a message while already waiting on a blocking request -- aborting!" << LL_ENDL; + } + + // Incoming message from the plugin instance + bool passMessage = true; + + // FIXME: how should we handle queueing here? + + // Intercept certain base messages (responses to ones sent by this class) + { + // Decode this message + LLPluginMessage parsed; + parsed.parse(message); + + if(parsed.hasValue("blocking_request")) + { + mBlockingRequest = true; + } + + std::string message_class = parsed.getClass(); + if(message_class == "base") + { + std::string message_name = parsed.getName(); + if(message_name == "init_response") + { + // The plugin has finished initializing. + setState(STATE_RUNNING); + + // Don't pass this message up to the parent + passMessage = false; + + LLPluginMessage new_message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin_response"); + LLSD versions = parsed.getValueLLSD("versions"); + new_message.setValueLLSD("versions", versions); + + if(parsed.hasValue("plugin_version")) + { + std::string plugin_version = parsed.getValue("plugin_version"); + new_message.setValueLLSD("plugin_version", plugin_version); + } + + // Let the parent know it's loaded and initialized. + sendMessageToParent(new_message); + } + else if(message_name == "shm_remove_response") + { + // Don't pass this message up to the parent + passMessage = false; + + std::string name = parsed.getValue("name"); + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + // detach the shared memory region + iter->second->detach(); + + // and remove it from our map + mSharedMemoryRegions.erase(iter); + + // Finally, send the response to the parent. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove_response"); + message.setValue("name", name); + sendMessageToParent(message); + } + else + { + LL_WARNS("Plugin") << "shm_remove_response for unknown memory segment!" << LL_ENDL; + } + } + } + } + + if(passMessage) + { + LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL; + writeMessageRaw(message); + } + + while(mBlockingRequest) + { + // The plugin wants to block and wait for a response to this message. + sleep(mSleepTime); // this will pump the message pipe and process messages + + if(mBlockingResponseReceived || mSocketError != APR_SUCCESS || (mMessagePipe == NULL)) + { + // Response has been received, or we've hit an error state. Stop waiting. + mBlockingRequest = false; + mBlockingResponseReceived = false; + } + } +} + + +void LLPluginProcessChild::setState(EState state) +{ + LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL; + mState = state; +}; + +void LLPluginProcessChild::deliverQueuedMessages() +{ + if(!mBlockingRequest) + { + while(!mMessageQueue.empty()) + { + receiveMessageRaw(mMessageQueue.front()); + mMessageQueue.pop(); + } + } +} diff --git a/linden/indra/llplugin/llpluginprocesschild.h b/linden/indra/llplugin/llpluginprocesschild.h new file mode 100755 index 000000000..5d643d792 --- /dev/null +++ b/linden/indra/llplugin/llpluginprocesschild.h @@ -0,0 +1,121 @@ +/** + * @file llpluginprocesschild.h + * @brief LLPluginProcessChild handles the child side of the external-process plugin API. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LL_LLPLUGINPROCESSCHILD_H +#define LL_LLPLUGINPROCESSCHILD_H + +#include <queue> //imprudence + +#include "llpluginmessage.h" +#include "llpluginmessagepipe.h" +#include "llplugininstance.h" +#include "llhost.h" +#include "llpluginsharedmemory.h" + +class LLPluginInstance; + +class LLPluginProcessChild: public LLPluginMessagePipeOwner, public LLPluginInstanceMessageListener +{ + LOG_CLASS(LLPluginProcessChild); +public: + LLPluginProcessChild(); + ~LLPluginProcessChild(); + + void init(U32 launcher_port); + void idle(void); + void sleep(F64 seconds); + void pump(); + + // returns true if the plugin is in the steady state (processing messages) + bool isRunning(void); + + // returns true if the plugin is unloaded or we're in an unrecoverable error state. + bool isDone(void); + + void killSockets(void); + + F64 getSleepTime(void) const { return mSleepTime; }; + + void sendMessageToPlugin(const LLPluginMessage &message); + void sendMessageToParent(const LLPluginMessage &message); + + // Inherited from LLPluginMessagePipeOwner + /* virtual */ void receiveMessageRaw(const std::string &message); + + // Inherited from LLPluginInstanceMessageListener + /* virtual */ void receivePluginMessage(const std::string &message); + +private: + + enum EState + { + STATE_UNINITIALIZED, + STATE_INITIALIZED, // init() has been called + STATE_CONNECTED, // connected back to launcher + STATE_PLUGIN_LOADING, // plugin library needs to be loaded + STATE_PLUGIN_LOADED, // plugin library has been loaded + STATE_PLUGIN_INITIALIZING, // plugin is processing init message + STATE_RUNNING, // steady state (processing messages) + STATE_UNLOADING, // plugin has sent shutdown_response and needs to be unloaded + STATE_UNLOADED, // plugin has been unloaded + STATE_ERROR, // generic bailout state + STATE_DONE // state machine will sit in this state after either error or normal termination. + }; + void setState(EState state); + + EState mState; + + LLHost mLauncherHost; + LLSocket::ptr_t mSocket; + + std::string mPluginFile; + + LLPluginInstance *mInstance; + + typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType; + sharedMemoryRegionsType mSharedMemoryRegions; + + LLTimer mHeartbeat; + F64 mSleepTime; + F64 mCPUElapsed; + bool mBlockingRequest; + bool mBlockingResponseReceived; + std::queue<std::string> mMessageQueue; + + void deliverQueuedMessages(); + +}; + +#endif // LL_LLPLUGINPROCESSCHILD_H diff --git a/linden/indra/llplugin/llpluginprocessparent.cpp b/linden/indra/llplugin/llpluginprocessparent.cpp new file mode 100755 index 000000000..2cb6b2832 --- /dev/null +++ b/linden/indra/llplugin/llpluginprocessparent.cpp @@ -0,0 +1,1159 @@ +/** + * @file llpluginprocessparent.cpp + * @brief LLPluginProcessParent handles the parent side of the external-process plugin API. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" + +#include "llpluginprocessparent.h" +#include "llpluginmessagepipe.h" +#include "llpluginmessageclasses.h" + +#include "llapr.h" + +//virtual +LLPluginProcessParentOwner::~LLPluginProcessParentOwner() +{ + +} + +bool LLPluginProcessParent::sUseReadThread = false; +apr_pollset_t *LLPluginProcessParent::sPollSet = NULL; +AIAPRPool LLPluginProcessParent::sPollSetPool; +bool LLPluginProcessParent::sPollsetNeedsRebuild = false; +LLMutex *LLPluginProcessParent::sInstancesMutex; +std::list<LLPluginProcessParent*> LLPluginProcessParent::sInstances; +LLThread *LLPluginProcessParent::sReadThread = NULL; + + +class LLPluginProcessParentPollThread: public LLThread +{ +public: + LLPluginProcessParentPollThread() : + LLThread("LLPluginProcessParentPollThread") + { + } +protected: + // Inherited from LLThread + /*virtual*/ void run(void) + { + while(!isQuitting() && LLPluginProcessParent::getUseReadThread()) + { + LLPluginProcessParent::poll(0.1f); + checkPause(); + } + + // Final poll to clean up the pollset, etc. + LLPluginProcessParent::poll(0.0f); + } + + // Inherited from LLThread + /*virtual*/ bool runCondition(void) + { + return(LLPluginProcessParent::canPollThreadRun()); + } + +}; + +LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner) +{ + if(!sInstancesMutex) + { + sInstancesMutex = new LLMutex; + } + + mOwner = owner; + mBoundPort = 0; + mState = STATE_UNINITIALIZED; + mSleepTime = 0.0; + mCPUUsage = 0.0; + mDisableTimeout = false; + mDebug = false; + mBlocked = false; + mPolledInput = false; + mPollFD.client_data = NULL; + mPollFDPool.create(); + + mPluginLaunchTimeout = 60.0f; + mPluginLockupTimeout = 15.0f; + + // Don't start the timer here -- start it when we actually launch the plugin process. + mHeartbeat.stop(); + + + // Don't add to the global list until fully constructed. + { + LLMutexLock lock(sInstancesMutex); + sInstances.push_back(this); + } +} + +LLPluginProcessParent::~LLPluginProcessParent() +{ + LL_DEBUGS("Plugin") << "destructor" << LL_ENDL; + + // Remove from the global list before beginning destruction. + { + // Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll() + LLMutexLock lock(sInstancesMutex); + { + LLMutexLock lock2(&mIncomingQueueMutex); + sInstances.remove(this); + } + } + + // Destroy any remaining shared memory regions + sharedMemoryRegionsType::iterator iter; + while((iter = mSharedMemoryRegions.begin()) != mSharedMemoryRegions.end()) + { + // destroy the shared memory region + iter->second->destroy(); + + // and remove it from our map + mSharedMemoryRegions.erase(iter); + } + + mProcess.kill(); + killSockets(); +} + +void LLPluginProcessParent::killSockets(void) +{ + { + LLMutexLock lock(&mIncomingQueueMutex); + killMessagePipe(); + } + + mListenSocket.reset(); + mSocket.reset(); +} + +void LLPluginProcessParent::errorState(void) +{ + if(mState < STATE_RUNNING) + setState(STATE_LAUNCH_FAILURE); + else + setState(STATE_ERROR); +} + +void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug) +{ + mProcess.setExecutable(launcher_filename); + mPluginFile = plugin_filename; + mCPUUsage = 0.0f; + mDebug = debug; + setState(STATE_INITIALIZED); +} + +bool LLPluginProcessParent::accept() +{ + bool result = false; + apr_status_t status = APR_EGENERAL; + + mSocket = LLSocket::create(status, mListenSocket); + + if(status == APR_SUCCESS) + { +// llinfos << "SUCCESS" << llendl; + // Success. Create a message pipe on the new socket + new LLPluginMessagePipe(this, mSocket); + + result = true; + } + else + { + mSocket.reset(); + // EAGAIN means "No incoming connections". This is not an error. + if (!APR_STATUS_IS_EAGAIN(status)) + { + // Some other error. + ll_apr_warn_status(status); + errorState(); + } + } + + return result; +} + +void LLPluginProcessParent::idle(void) +{ + bool idle_again; + + do + { + // process queued messages + mIncomingQueueMutex.lock(); + while(!mIncomingQueue.empty()) + { + LLPluginMessage message = mIncomingQueue.front(); + mIncomingQueue.pop(); + mIncomingQueueMutex.unlock(); + + receiveMessage(message); + + mIncomingQueueMutex.lock(); + } + + mIncomingQueueMutex.unlock(); + + // Give time to network processing + if(mMessagePipe) + { + // Drain any queued outgoing messages + mMessagePipe->pumpOutput(); + + // Only do input processing here if this instance isn't in a pollset. + if(!mPolledInput) + { + mMessagePipe->pumpInput(); + } + } + + if(mState <= STATE_RUNNING) + { + if(APR_STATUS_IS_EOF(mSocketError)) + { + // Plugin socket was closed. This covers both normal plugin termination and plugin crashes. + errorState(); + } + else if(mSocketError != APR_SUCCESS) + { + // The socket is in an error state -- the plugin is gone. + LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL; + errorState(); + } + } + + // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState(). + // USE THIS CAREFULLY, since it can starve other code. Specifically make sure there's no way to get into a closed cycle and never return. + // When in doubt, don't do it. + idle_again = false; + switch(mState) + { + case STATE_UNINITIALIZED: + break; + + case STATE_INITIALIZED: + { + + apr_status_t status = APR_SUCCESS; + apr_sockaddr_t* addr = NULL; + mListenSocket = LLSocket::create(LLSocket::STREAM_TCP); + mBoundPort = 0; + + // This code is based on parts of LLSocket::create() in lliosocket.cpp. + + status = apr_sockaddr_info_get( + &addr, + "127.0.0.1", + APR_INET, + 0, // port 0 = ephemeral ("find me a port") + 0, + AIAPRRootPool::get()()); + + if(ll_apr_warn_status(status)) + { + killSockets(); + errorState(); + break; + } + + // This allows us to reuse the address on quick down/up. This is unlikely to create problems. + ll_apr_warn_status(apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_REUSEADDR, 1)); + + status = apr_socket_bind(mListenSocket->getSocket(), addr); + if(ll_apr_warn_status(status)) + { + killSockets(); + errorState(); + break; + } + + // Get the actual port the socket was bound to + { + apr_sockaddr_t* bound_addr = NULL; + if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket()))) + { + killSockets(); + errorState(); + break; + } + mBoundPort = bound_addr->port; + + if(mBoundPort == 0) + { + LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL; + + killSockets(); + errorState(); + break; + } + } + + LL_DEBUGS("Plugin") << "Bound tcp socket to port: " << addr->port << LL_ENDL; + + // Make the listen socket non-blocking + status = apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_NONBLOCK, 1); + if(ll_apr_warn_status(status)) + { + killSockets(); + errorState(); + break; + } + + apr_socket_timeout_set(mListenSocket->getSocket(), 0); + if(ll_apr_warn_status(status)) + { + killSockets(); + errorState(); + break; + } + + // If it's a stream based socket, we need to tell the OS + // to keep a queue of incoming connections for ACCEPT. + status = apr_socket_listen( + mListenSocket->getSocket(), + 10); // FIXME: Magic number for queue size + + if(ll_apr_warn_status(status)) + { + killSockets(); + errorState(); + break; + } + + // If we got here, we're listening. + setState(STATE_LISTENING); + } + break; + + case STATE_LISTENING: + { + // Launch the plugin process. + + // Only argument to the launcher is the port number we're listening on + std::stringstream stream; + stream << mBoundPort; + mProcess.addArgument(stream.str()); + if(mProcess.launch() != 0) + { + errorState(); + } + else + { + if(mDebug) + { + #if LL_DARWIN + // If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue. + + // The command we're constructing would look like this on the command line: + // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell' + + std::stringstream cmd; + + mDebugger.setExecutable("/usr/bin/osascript"); + mDebugger.addArgument("-e"); + mDebugger.addArgument("tell application \"Terminal\""); + mDebugger.addArgument("-e"); + cmd << "set win to do script \"gdb -pid " << mProcess.getProcessID() << "\""; + mDebugger.addArgument(cmd.str()); + mDebugger.addArgument("-e"); + mDebugger.addArgument("do script \"continue\" in win"); + mDebugger.addArgument("-e"); + mDebugger.addArgument("end tell"); + mDebugger.launch(); + + #elif LL_LINUX + + std::stringstream cmd; + + mDebugger.setExecutable("/usr/bin/gnome-terminal"); + mDebugger.addArgument("--geometry=165x24-0+0"); + mDebugger.addArgument("-e"); + cmd << "/usr/bin/gdb -n /proc/" << mProcess.getProcessID() << "/exe " << mProcess.getProcessID(); + mDebugger.addArgument(cmd.str()); + mDebugger.launch(); + + #endif + } + + // This will allow us to time out if the process never starts. + mHeartbeat.start(); + mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout); + setState(STATE_LAUNCHED); + } + } + break; + + case STATE_LAUNCHED: + // waiting for the plugin to connect + if(pluginLockedUpOrQuit()) + { + errorState(); + } + else + { + // Check for the incoming connection. + if(accept()) + { + // Stop listening on the server port + mListenSocket.reset(); + setState(STATE_CONNECTED); + } + } + break; + + case STATE_CONNECTED: + // waiting for hello message from the plugin + + if(pluginLockedUpOrQuit()) + { + errorState(); + } + break; + + case STATE_HELLO: + LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL; + + // Send the message to load the plugin + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin"); + message.setValue("file", mPluginFile); + sendMessage(message); + } + + setState(STATE_LOADING); + break; + + case STATE_LOADING: + // The load_plugin_response message will kick us from here into STATE_RUNNING + if(pluginLockedUpOrQuit()) + { + errorState(); + } + break; + + case STATE_RUNNING: + if(pluginLockedUpOrQuit()) + { + errorState(); + } + break; + + case STATE_EXITING: + if(!mProcess.isRunning()) + { + setState(STATE_CLEANUP); + } + else if(pluginLockedUp()) + { + LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL; + errorState(); + } + break; + + case STATE_LAUNCH_FAILURE: + if(mOwner != NULL) + { + mOwner->pluginLaunchFailed(); + } + setState(STATE_CLEANUP); + break; + + case STATE_ERROR: + if(mOwner != NULL) + { + mOwner->pluginDied(); + } + setState(STATE_CLEANUP); + break; + + case STATE_CLEANUP: + mProcess.kill(); + killSockets(); + setState(STATE_DONE); + break; + + + case STATE_DONE: + // just sit here. + break; + + } + + } while (idle_again); +} + +bool LLPluginProcessParent::isLoading(void) +{ + bool result = false; + + if(mState <= STATE_LOADING) + result = true; + + return result; +} + +bool LLPluginProcessParent::isRunning(void) +{ + bool result = false; + + if(mState == STATE_RUNNING) + result = true; + + return result; +} + +bool LLPluginProcessParent::isDone(void) +{ + bool result = false; + + if(mState == STATE_DONE) + result = true; + + return result; +} + +void LLPluginProcessParent::setSleepTime(F64 sleep_time, bool force_send) +{ + if(force_send || (sleep_time != mSleepTime)) + { + // Cache the time locally + mSleepTime = sleep_time; + + if(canSendMessage()) + { + // and send to the plugin. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "sleep_time"); + message.setValueReal("time", mSleepTime); + sendMessage(message); + } + else + { + // Too early to send -- the load_plugin_response message will trigger us to send mSleepTime later. + } + } +} + +void LLPluginProcessParent::sendMessage(const LLPluginMessage &message) +{ + if(message.hasValue("blocking_response")) + { + mBlocked = false; + + // reset the heartbeat timer, since there will have been no heartbeats while the plugin was blocked. + mHeartbeat.setTimerExpirySec(mPluginLockupTimeout); + } + + std::string buffer = message.generate(); + LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL; + writeMessageRaw(buffer); + + // Try to send message immediately. + if(mMessagePipe) + { + mMessagePipe->pumpOutput(); + } +} + +//virtual +void LLPluginProcessParent::setMessagePipe(LLPluginMessagePipe *message_pipe) +{ + bool update_pollset = false; + + if(mMessagePipe) + { + // Unsetting an existing message pipe -- remove from the pollset + mPollFD.client_data = NULL; + + // pollset needs an update + update_pollset = true; + } + if(message_pipe != NULL) + { + // Set up the apr_pollfd_t + + mPollFD.p = mPollFDPool(); + mPollFD.desc_type = APR_POLL_SOCKET; + mPollFD.reqevents = APR_POLLIN|APR_POLLERR|APR_POLLHUP; + mPollFD.rtnevents = 0; + mPollFD.desc.s = mSocket->getSocket(); + mPollFD.client_data = (void*)this; + + // pollset needs an update + update_pollset = true; + } + + mMessagePipe = message_pipe; + + if(update_pollset) + { + dirtyPollSet(); + } +} + +//static +void LLPluginProcessParent::dirtyPollSet() +{ + sPollsetNeedsRebuild = true; + + if(sReadThread) + { + LL_DEBUGS("PluginPoll") << "unpausing read thread " << LL_ENDL; + sReadThread->unpause(); + } +} + +void LLPluginProcessParent::updatePollset() +{ + if(!sInstancesMutex) + { + // No instances have been created yet. There's no work to do. + return; + } + + LLMutexLock lock(sInstancesMutex); + + if(sPollSet) + { + LL_DEBUGS("PluginPoll") << "destroying pollset " << sPollSet << LL_ENDL; + // delete the existing pollset. + apr_pollset_destroy(sPollSet); + sPollSet = NULL; + sPollSetPool.destroy(); + } + + std::list<LLPluginProcessParent*>::iterator iter; + int count = 0; + + // Count the number of instances that want to be in the pollset + for(iter = sInstances.begin(); iter != sInstances.end(); iter++) + { + (*iter)->mPolledInput = false; + if((*iter)->mPollFD.client_data) + { + // This instance has a socket that needs to be polled. + ++count; + } + } + + if(sUseReadThread && sReadThread && !sReadThread->isQuitting()) + { + if(!sPollSet && (count > 0)) + { +#ifdef APR_POLLSET_NOCOPY + // The pollset doesn't exist yet. Create it now. + sPollSetPool.create(); + apr_status_t status = apr_pollset_create(&sPollSet, count, sPollSetPool(), APR_POLLSET_NOCOPY); + if(status != APR_SUCCESS) + { +#endif // APR_POLLSET_NOCOPY + LL_WARNS("PluginPoll") << "Couldn't create pollset. Falling back to non-pollset mode." << LL_ENDL; + sPollSet = NULL; + sPollSetPool.destroy(); +#ifdef APR_POLLSET_NOCOPY + } + else + { + LL_DEBUGS("PluginPoll") << "created pollset " << sPollSet << LL_ENDL; + + // Pollset was created, add all instances to it. + for(iter = sInstances.begin(); iter != sInstances.end(); iter++) + { + if((*iter)->mPollFD.client_data) + { + status = apr_pollset_add(sPollSet, &((*iter)->mPollFD)); + if(status == APR_SUCCESS) + { + (*iter)->mPolledInput = true; + } + else + { + LL_WARNS("PluginPoll") << "apr_pollset_add failed with status " << status << LL_ENDL; + } + } + } + } +#endif // APR_POLLSET_NOCOPY + } + } +} + +void LLPluginProcessParent::setUseReadThread(bool use_read_thread) +{ + if(sUseReadThread != use_read_thread) + { + sUseReadThread = use_read_thread; + + if(sUseReadThread) + { + if(!sReadThread) + { + // start up the read thread + LL_INFOS("PluginPoll") << "creating read thread " << LL_ENDL; + + // make sure the pollset gets rebuilt. + sPollsetNeedsRebuild = true; + + sReadThread = new LLPluginProcessParentPollThread; + sReadThread->start(); + } + } + else + { + if(sReadThread) + { + // shut down the read thread + LL_INFOS("PluginPoll") << "destroying read thread " << LL_ENDL; + delete sReadThread; + sReadThread = NULL; + } + } + + } +} + +void LLPluginProcessParent::poll(F64 timeout) +{ + if(sPollsetNeedsRebuild || !sUseReadThread) + { + sPollsetNeedsRebuild = false; + updatePollset(); + } + + if(sPollSet) + { + apr_status_t status; + apr_int32_t count; + const apr_pollfd_t *descriptors; + status = apr_pollset_poll(sPollSet, (apr_interval_time_t)(timeout * 1000000), &count, &descriptors); + if(status == APR_SUCCESS) + { + // One or more of the descriptors signalled. Call them. + for(int i = 0; i < count; i++) + { + LLPluginProcessParent *self = (LLPluginProcessParent *)(descriptors[i].client_data); + // NOTE: the descriptor returned here is actually a COPY of the original (even though we create the pollset with APR_POLLSET_NOCOPY). + // This means that even if the parent has set its mPollFD.client_data to NULL, the old pointer may still there in this descriptor. + // It's even possible that the old pointer no longer points to a valid LLPluginProcessParent. + // This means that we can't safely dereference the 'self' pointer here without some extra steps... + if(self) + { + // Make sure this pointer is still in the instances list + bool valid = false; + { + LLMutexLock lock(sInstancesMutex); + for(std::list<LLPluginProcessParent*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter) + { + if(*iter == self) + { + // Lock the instance's mutex before unlocking the global mutex. + // This avoids a possible race condition where the instance gets deleted between this check and the servicePoll() call. + self->mIncomingQueueMutex.lock(); + valid = true; + break; + } + } + } + + if(valid) + { + // The instance is still valid. + // Pull incoming messages off the socket + self->servicePoll(); + self->mIncomingQueueMutex.unlock(); + } + else + { + LL_DEBUGS("PluginPoll") << "detected deleted instance " << self << LL_ENDL; + } + + } + } + } + else if(APR_STATUS_IS_TIMEUP(status)) + { + // timed out with no incoming data. Just return. + } + else if(status == EBADF) + { + // This happens when one of the file descriptors in the pollset is destroyed, which happens whenever a plugin's socket is closed. + // The pollset has been or will be recreated, so just return. + LL_DEBUGS("PluginPoll") << "apr_pollset_poll returned EBADF" << LL_ENDL; + } + else if(status != APR_SUCCESS) + { + LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << LL_ENDL; + } + } +} + +void LLPluginProcessParent::servicePoll() +{ + bool result = true; + + // poll signalled on this object's socket. Try to process incoming messages. + if(mMessagePipe) + { + result = mMessagePipe->pumpInput(0.0f); + } + + if(!result) + { + // If we got a read error on input, remove this pipe from the pollset + apr_pollset_remove(sPollSet, &mPollFD); + + // and tell the code not to re-add it + mPollFD.client_data = NULL; + } +} + +void LLPluginProcessParent::receiveMessageRaw(const std::string &message) +{ + LL_DEBUGS("Plugin") << "Received: " << message << LL_ENDL; + + LLPluginMessage parsed; + if(parsed.parse(message) != -1) + { + if(parsed.hasValue("blocking_request")) + { + mBlocked = true; + } + + if(mPolledInput) + { + // This is being called on the polling thread -- only do minimal processing/queueing. + receiveMessageEarly(parsed); + } + else + { + // This is not being called on the polling thread -- do full message processing at this time. + receiveMessage(parsed); + } + } +} + +void LLPluginProcessParent::receiveMessageEarly(const LLPluginMessage &message) +{ + // NOTE: this function will be called from the polling thread. It will be called with mIncomingQueueMutex _already locked_. + + bool handled = false; + + std::string message_class = message.getClass(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) + { + // no internal messages need to be handled early. + } + else + { + // Call out to the owner and see if they to reply + // TODO: Should this only happen when blocked? + if(mOwner != NULL) + { + handled = mOwner->receivePluginMessageEarly(message); + } + } + + if(!handled) + { + // any message that wasn't handled early needs to be queued. + mIncomingQueue.push(message); + } +} + +void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) +{ + std::string message_class = message.getClass(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) + { + // internal messages should be handled here + std::string message_name = message.getName(); + if(message_name == "hello") + { + if(mState == STATE_CONNECTED) + { + // Plugin host has launched. Tell it which plugin to load. + setState(STATE_HELLO); + } + else + { + LL_WARNS("Plugin") << "received hello message in wrong state -- bailing out" << LL_ENDL; + errorState(); + } + + } + else if(message_name == "load_plugin_response") + { + if(mState == STATE_LOADING) + { + // Plugin has been loaded. + + mPluginVersionString = message.getValue("plugin_version"); + LL_INFOS("Plugin") << "plugin version string: " << mPluginVersionString << LL_ENDL; + + // Check which message classes/versions the plugin supports. + // TODO: check against current versions + // TODO: kill plugin on major mismatches? + mMessageClassVersions = message.getValueLLSD("versions"); + LLSD::map_iterator iter; + for(iter = mMessageClassVersions.beginMap(); iter != mMessageClassVersions.endMap(); iter++) + { + LL_INFOS("Plugin") << "message class: " << iter->first << " -> version: " << iter->second.asString() << LL_ENDL; + } + + // Send initial sleep time + setSleepTime(mSleepTime, true); + + setState(STATE_RUNNING); + } + else + { + LL_WARNS("Plugin") << "received load_plugin_response message in wrong state -- bailing out" << LL_ENDL; + errorState(); + } + } + else if(message_name == "heartbeat") + { + // this resets our timer. + mHeartbeat.setTimerExpirySec(mPluginLockupTimeout); + + mCPUUsage = message.getValueReal("cpu_usage"); + + LL_DEBUGS("Plugin") << "cpu usage reported as " << mCPUUsage << LL_ENDL; + + } + else if(message_name == "shm_add_response") + { + // Nothing to do here. + } + else if(message_name == "shm_remove_response") + { + std::string name = message.getValue("name"); + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + + if(iter != mSharedMemoryRegions.end()) + { + // destroy the shared memory region + iter->second->destroy(); + + // and remove it from our map + mSharedMemoryRegions.erase(iter); + } + } + else + { + LL_WARNS("Plugin") << "Unknown internal message from child: " << message_name << LL_ENDL; + } + } + else + { + if(mOwner != NULL) + { + mOwner->receivePluginMessage(message); + } + } +} + +std::string LLPluginProcessParent::addSharedMemory(size_t size) +{ + std::string name; + + LLPluginSharedMemory *region = new LLPluginSharedMemory; + + // This is a new region + if(region->create(size)) + { + name = region->getName(); + + mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region)); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add"); + message.setValue("name", name); + message.setValueS32("size", (S32)size); + sendMessage(message); + } + else + { + LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL; + + // Don't leak + delete region; + } + + return name; +} + +void LLPluginProcessParent::removeSharedMemory(const std::string &name) +{ + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + + if(iter != mSharedMemoryRegions.end()) + { + // This segment exists. Send the message to the child to unmap it. The response will cause the parent to unmap our end. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove"); + message.setValue("name", name); + sendMessage(message); + } + else + { + LL_WARNS("Plugin") << "Request to remove an unknown shared memory segment." << LL_ENDL; + } +} +size_t LLPluginProcessParent::getSharedMemorySize(const std::string &name) +{ + size_t result = 0; + + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + result = iter->second->getSize(); + } + + return result; +} +void *LLPluginProcessParent::getSharedMemoryAddress(const std::string &name) +{ + void *result = NULL; + + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + result = iter->second->getMappedAddress(); + } + + return result; +} + +std::string LLPluginProcessParent::getMessageClassVersion(const std::string &message_class) +{ + std::string result; + + if(mMessageClassVersions.has(message_class)) + { + result = mMessageClassVersions[message_class].asString(); + } + + return result; +} + +std::string LLPluginProcessParent::getPluginVersion(void) +{ + return mPluginVersionString; +} + +void LLPluginProcessParent::setState(EState state) +{ + LL_DEBUGS("Plugin") << "setting state to " << stateToString(state) << LL_ENDL; + mState = state; +}; + +bool LLPluginProcessParent::pluginLockedUpOrQuit() +{ + bool result = false; + + if(!mProcess.isRunning()) + { + LL_WARNS("Plugin") << "child exited" << LL_ENDL; + result = true; + } + else if(pluginLockedUp()) + { + LL_WARNS("Plugin") << "timeout" << LL_ENDL; + result = true; + } + + return result; +} + +bool LLPluginProcessParent::pluginLockedUp() +{ + if(mDisableTimeout || mDebug || mBlocked) + { + // Never time out a plugin process in these cases. + return false; + } + + // If the timer is running and has expired, the plugin has locked up. + return (mHeartbeat.getStarted() && mHeartbeat.hasExpired()); +} + +std::string LLPluginProcessParent::stateToString(EState state) +{ + std::string eng = "unknown plugin state"; + switch (state) + { + case STATE_UNINITIALIZED: + eng = "STATE_UNINITIALIZED"; + break; + case STATE_INITIALIZED: + eng = "STATE_INITIALIZED - init() has been called"; + break; + case STATE_LISTENING: + eng = "STATE_LISTENING - listening for incoming connection"; + break; + case STATE_LAUNCHED: + eng = "STATE_LAUNCHED - process has been launched"; + break; + case STATE_CONNECTED: + eng = "STATE_CONNECTED - process has connected"; + break; + case STATE_HELLO: + eng = "STATE_HELLO - first message from the plugin process has been received"; + break; + case STATE_LOADING: + eng = "STATE_LOADING - process has been asked to load the plugin"; + break; + case STATE_RUNNING: + eng = "STATE_RUNNING - plugin running"; + break; + case STATE_LAUNCH_FAILURE: + eng = "STATE_LAUNCH_FAILURE - failure before plugin loaded"; + break; + case STATE_ERROR: + eng = "STATE_ERROR - generic bailout state"; + break; + case STATE_CLEANUP: + eng = "STATE_CLEANUP - clean everything up"; + break; + case STATE_EXITING: + eng = "STATE_EXITING - tried to kill process, waiting for it to exit"; + break; + case STATE_DONE: + eng = "STATE_DONE - plugin done"; + break; + default: + break; + } + + return llformat("(%d) ", (S32)state) + eng; +} diff --git a/linden/indra/llplugin/llpluginprocessparent.h b/linden/indra/llplugin/llpluginprocessparent.h new file mode 100755 index 000000000..bba3643d6 --- /dev/null +++ b/linden/indra/llplugin/llpluginprocessparent.h @@ -0,0 +1,204 @@ +/** + * @file llpluginprocessparent.h + * @brief LLPluginProcessParent handles the parent side of the external-process plugin API. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LL_LLPLUGINPROCESSPARENT_H +#define LL_LLPLUGINPROCESSPARENT_H + +#include <queue> //imprudence + +#include "llapr.h" +#include "llprocesslauncher.h" +#include "llpluginmessage.h" +#include "llpluginmessagepipe.h" +#include "llpluginsharedmemory.h" + +#include "lliosocket.h" +#include "llthread.h" + +class LLPluginProcessParentOwner +{ +public: + virtual ~LLPluginProcessParentOwner(); + virtual void receivePluginMessage(const LLPluginMessage &message) = 0; + virtual bool receivePluginMessageEarly(const LLPluginMessage &message) {return false;}; + // This will only be called when the plugin has died unexpectedly + virtual void pluginLaunchFailed() {}; + virtual void pluginDied() {}; +}; + +class LLPluginProcessParent : public LLPluginMessagePipeOwner +{ + LOG_CLASS(LLPluginProcessParent); +public: + LLPluginProcessParent(LLPluginProcessParentOwner *owner); + ~LLPluginProcessParent(); + + void init(const std::string &launcher_filename, + const std::string &plugin_filename, + bool debug); + + void idle(void); + + // returns true if the plugin is on its way to steady state + bool isLoading(void); + + // returns true if the plugin is in the steady state (processing messages) + bool isRunning(void); + + // returns true if the process has exited or we've had a fatal error + bool isDone(void); + + // returns true if the process is currently waiting on a blocking request + bool isBlocked(void) { return mBlocked; }; + + void killSockets(void); + + // Go to the proper error state + void errorState(void); + + void setSleepTime(F64 sleep_time, bool force_send = false); + F64 getSleepTime(void) const { return mSleepTime; }; + + void sendMessage(const LLPluginMessage &message); + + void receiveMessage(const LLPluginMessage &message); + + // Inherited from LLPluginMessagePipeOwner + /*virtual*/ void receiveMessageRaw(const std::string &message); + /*virtual*/ void receiveMessageEarly(const LLPluginMessage &message); + /*virtual*/ void setMessagePipe(LLPluginMessagePipe *message_pipe) ; + + // This adds a memory segment shared with the client, generating a name for the segment. The name generated is guaranteed to be unique on the host. + // The caller must call removeSharedMemory first (and wait until getSharedMemorySize returns 0 for the indicated name) before re-adding a segment with the same name. + std::string addSharedMemory(size_t size); + // Negotiates for the removal of a shared memory segment. It is the caller's responsibility to ensure that nothing touches the memory + // after this has been called, since the segment will be unmapped shortly thereafter. + void removeSharedMemory(const std::string &name); + size_t getSharedMemorySize(const std::string &name); + void *getSharedMemoryAddress(const std::string &name); + + // Returns the version string the plugin indicated for the message class, or an empty string if that class wasn't in the list. + std::string getMessageClassVersion(const std::string &message_class); + + std::string getPluginVersion(void); + + bool getDisableTimeout() { return mDisableTimeout; }; + void setDisableTimeout(bool disable) { mDisableTimeout = disable; }; + + void setLaunchTimeout(F32 timeout) { mPluginLaunchTimeout = timeout; }; + void setLockupTimeout(F32 timeout) { mPluginLockupTimeout = timeout; }; + + F64 getCPUUsage() { return mCPUUsage; }; + + static void poll(F64 timeout); + static bool canPollThreadRun() { return (sPollSet || sPollsetNeedsRebuild || sUseReadThread); }; + static void setUseReadThread(bool use_read_thread); + static bool getUseReadThread() { return sUseReadThread; }; +private: + + enum EState + { + STATE_UNINITIALIZED, + STATE_INITIALIZED, // init() has been called + STATE_LISTENING, // listening for incoming connection + STATE_LAUNCHED, // process has been launched + STATE_CONNECTED, // process has connected + STATE_HELLO, // first message from the plugin process has been received + STATE_LOADING, // process has been asked to load the plugin + STATE_RUNNING, // + STATE_LAUNCH_FAILURE, // Failure before plugin loaded + STATE_ERROR, // generic bailout state + STATE_CLEANUP, // clean everything up + STATE_EXITING, // Tried to kill process, waiting for it to exit + STATE_DONE // + + }; + EState mState; + void setState(EState state); + std::string stateToString(EState state); + + bool pluginLockedUp(); + bool pluginLockedUpOrQuit(); + + bool accept(); + + LLSocket::ptr_t mListenSocket; + LLSocket::ptr_t mSocket; + U32 mBoundPort; + + LLProcessLauncher mProcess; + + std::string mPluginFile; + + LLPluginProcessParentOwner *mOwner; + + typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType; + sharedMemoryRegionsType mSharedMemoryRegions; + + LLSD mMessageClassVersions; + std::string mPluginVersionString; + + LLTimer mHeartbeat; + F64 mSleepTime; + F64 mCPUUsage; + + bool mDisableTimeout; + bool mDebug; + bool mBlocked; + bool mPolledInput; + + LLProcessLauncher mDebugger; + + F32 mPluginLaunchTimeout; // Somewhat longer timeout for initial launch. + F32 mPluginLockupTimeout; // If we don't receive a heartbeat in this many seconds, we declare the plugin locked up. + + static bool sUseReadThread; + apr_pollfd_t mPollFD; + AIAPRPool mPollFDPool; + static apr_pollset_t *sPollSet; + static AIAPRPool sPollSetPool; + static bool sPollsetNeedsRebuild; + static LLMutex *sInstancesMutex; + static std::list<LLPluginProcessParent*> sInstances; + static void dirtyPollSet(); + static void updatePollset(); + void servicePoll(); + static LLThread *sReadThread; + + LLMutex mIncomingQueueMutex; + std::queue<LLPluginMessage> mIncomingQueue; +}; + +#endif // LL_LLPLUGINPROCESSPARENT_H diff --git a/linden/indra/llplugin/llpluginsharedmemory.cpp b/linden/indra/llplugin/llpluginsharedmemory.cpp new file mode 100755 index 000000000..6becb8dff --- /dev/null +++ b/linden/indra/llplugin/llpluginsharedmemory.cpp @@ -0,0 +1,521 @@ +/** + * @file llpluginsharedmemory.cpp + * LLPluginSharedMemory manages a shared memory segment for use by the LLPlugin API. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" + +#include "llpluginsharedmemory.h" + +#if LL_WINDOWS +#include <process.h> +#else // LL_WINDOWS +#include <sys/types.h> +#include <unistd.h> +#endif // LL_WINDOWS + +// on Mac and Linux, we use the native shm_open/mmap interface by using +// #define USE_SHM_OPEN_SHARED_MEMORY 1 +// in the appropriate sections below. + +// For Windows, use: +// #define USE_WIN32_SHARED_MEMORY 1 + +// If we ever want to fall back to the apr implementation for a platform, use: +// #define USE_APR_SHARED_MEMORY 1 + +#if LL_WINDOWS +// #define USE_APR_SHARED_MEMORY 1 + #define USE_WIN32_SHARED_MEMORY 1 +#elif LL_DARWIN + #define USE_SHM_OPEN_SHARED_MEMORY 1 +#elif LL_LINUX + #define USE_SHM_OPEN_SHARED_MEMORY 1 +#endif + + +// FIXME: This path thing is evil and unacceptable. +#if LL_WINDOWS + #define APR_SHARED_MEMORY_PREFIX_STRING "C:\\LLPlugin_" + // Apparnently using the "Global\\" prefix here only works from administrative accounts under Vista. + // Other options I've seen referenced are "Local\\" and "Session\\". + #define WIN32_SHARED_MEMORY_PREFIX_STRING "Local\\LL_" +#else + // mac and linux + #define APR_SHARED_MEMORY_PREFIX_STRING "/tmp/LLPlugin_" + #define SHM_OPEN_SHARED_MEMORY_PREFIX_STRING "/LL" +#endif + +#if USE_APR_SHARED_MEMORY + #include "llapr.h" + #include "apr_shm.h" +#elif USE_SHM_OPEN_SHARED_MEMORY + #include <sys/fcntl.h> + #include <sys/mman.h> + #include <errno.h> +#elif USE_WIN32_SHARED_MEMORY +# define WIN32_LEAN_AND_MEAN +# include <winsock2.h> +#include <windows.h> +#endif // USE_APR_SHARED_MEMORY + + +int LLPluginSharedMemory::sSegmentNumber = 0; + +std::string LLPluginSharedMemory::createName(void) +{ + std::stringstream newname; + +#if LL_WINDOWS + newname << GetCurrentProcessId(); +#else // LL_WINDOWS + newname << getpid(); +#endif // LL_WINDOWS + + newname << "_" << sSegmentNumber++; + + return newname.str(); +} + +/** + * @brief LLPluginSharedMemoryImpl is the platform-dependent implementation of LLPluginSharedMemory. TODO:DOC is this necessary/sufficient? kinda obvious. + * + */ +class LLPluginSharedMemoryPlatformImpl +{ +public: + LLPluginSharedMemoryPlatformImpl(); + ~LLPluginSharedMemoryPlatformImpl(); + +#if USE_APR_SHARED_MEMORY + apr_shm_t* mAprSharedMemory; +#elif USE_SHM_OPEN_SHARED_MEMORY + int mSharedMemoryFD; +#elif USE_WIN32_SHARED_MEMORY + HANDLE mMapFile; +#endif + +}; + +/** + * Constructor. Creates a shared memory segment. + */ +LLPluginSharedMemory::LLPluginSharedMemory() +{ + mSize = 0; + mMappedAddress = NULL; + mNeedsDestroy = false; + + mImpl = new LLPluginSharedMemoryPlatformImpl; +} + +/** + * Destructor. Uses destroy() and detach() to ensure shared memory segment is cleaned up. + */ +LLPluginSharedMemory::~LLPluginSharedMemory() +{ + if(mNeedsDestroy) + destroy(); + else + detach(); + + unlink(); + + delete mImpl; +} + +#if USE_APR_SHARED_MEMORY +// MARK: apr implementation + +LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl() +{ + mAprSharedMemory = NULL; +} + +LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl() +{ + +} + +bool LLPluginSharedMemory::map(void) +{ + mMappedAddress = apr_shm_baseaddr_get(mImpl->mAprSharedMemory); + if(mMappedAddress == NULL) + { + return false; + } + + return true; +} + +bool LLPluginSharedMemory::unmap(void) +{ + // This is a no-op under apr. + return true; +} + +bool LLPluginSharedMemory::close(void) +{ + // This is a no-op under apr. + return true; +} + +bool LLPluginSharedMemory::unlink(void) +{ + // This is a no-op under apr. + return true; +} + + +bool LLPluginSharedMemory::create(size_t size) +{ + mName = APR_SHARED_MEMORY_PREFIX_STRING; + mName += createName(); + mSize = size; + + mPool.create(); + apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), mPool()); + + if(ll_apr_warn_status(status)) + { + return false; + } + + mNeedsDestroy = true; + + return map(); +} + +bool LLPluginSharedMemory::destroy(void) +{ + if(mImpl->mAprSharedMemory) + { + apr_status_t status = apr_shm_destroy(mImpl->mAprSharedMemory); + if(ll_apr_warn_status(status)) + { + // TODO: Is this a fatal error? I think not... + } + mImpl->mAprSharedMemory = NULL; + } + mPool.destroy(); + return true; +} + +bool LLPluginSharedMemory::attach(const std::string &name, size_t size) +{ + mName = name; + mSize = size; + + mPool.create(); + apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), mPool() ); + + if(ll_apr_warn_status(status)) + { + return false; + } + + return map(); +} + + +bool LLPluginSharedMemory::detach(void) +{ + if(mImpl->mAprSharedMemory) + { + apr_status_t status = apr_shm_detach(mImpl->mAprSharedMemory); + if(ll_apr_warn_status(status)) + { + // TODO: Is this a fatal error? I think not... + } + mImpl->mAprSharedMemory = NULL; + } + mPool.destroy(); + + return true; +} + + +#elif USE_SHM_OPEN_SHARED_MEMORY +// MARK: shm_open/mmap implementation + +LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl() +{ + mSharedMemoryFD = -1; +} + +LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl() +{ +} + +bool LLPluginSharedMemory::map(void) +{ + mMappedAddress = ::mmap(NULL, mSize, PROT_READ | PROT_WRITE, MAP_SHARED, mImpl->mSharedMemoryFD, 0); + if(mMappedAddress == NULL) + { + return false; + } + + LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL; + + return true; +} + +bool LLPluginSharedMemory::unmap(void) +{ + if(mMappedAddress != NULL) + { + LL_DEBUGS("Plugin") << "calling munmap(" << mMappedAddress << ", " << mSize << ")" << LL_ENDL; + if(::munmap(mMappedAddress, mSize) == -1) + { + // TODO: Is this a fatal error? I think not... + } + + mMappedAddress = NULL; + } + + return true; +} + +bool LLPluginSharedMemory::close(void) +{ + if(mImpl->mSharedMemoryFD != -1) + { + LL_DEBUGS("Plugin") << "calling close(" << mImpl->mSharedMemoryFD << ")" << LL_ENDL; + if(::close(mImpl->mSharedMemoryFD) == -1) + { + // TODO: Is this a fatal error? I think not... + } + + mImpl->mSharedMemoryFD = -1; + } + return true; +} + +bool LLPluginSharedMemory::unlink(void) +{ + if(!mName.empty()) + { + if(::shm_unlink(mName.c_str()) == -1) + { + return false; + } + } + + return true; +} + + +bool LLPluginSharedMemory::create(size_t size) +{ + mName = SHM_OPEN_SHARED_MEMORY_PREFIX_STRING; + mName += createName(); + mSize = size; + + // Preemptive unlink, just in case something didn't get cleaned up. + unlink(); + + mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if(mImpl->mSharedMemoryFD == -1) + { + return false; + } + + mNeedsDestroy = true; + + if(::ftruncate(mImpl->mSharedMemoryFD, mSize) == -1) + { + return false; + } + + + return map(); +} + +bool LLPluginSharedMemory::destroy(void) +{ + unmap(); + close(); + + return true; +} + + +bool LLPluginSharedMemory::attach(const std::string &name, size_t size) +{ + mName = name; + mSize = size; + + mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); + if(mImpl->mSharedMemoryFD == -1) + { + return false; + } + + // unlink here so the segment will be cleaned up automatically after the last close. + unlink(); + + return map(); +} + +bool LLPluginSharedMemory::detach(void) +{ + unmap(); + close(); + return true; +} + +#elif USE_WIN32_SHARED_MEMORY +// MARK: Win32 CreateFileMapping-based implementation + +// Reference: http://msdn.microsoft.com/en-us/library/aa366551(VS.85).aspx + +LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl() +{ + mMapFile = NULL; +} + +LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl() +{ + +} + +bool LLPluginSharedMemory::map(void) +{ + mMappedAddress = MapViewOfFile( + mImpl->mMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + mSize); + + if(mMappedAddress == NULL) + { + LL_WARNS("Plugin") << "MapViewOfFile failed: " << GetLastError() << LL_ENDL; + return false; + } + + LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL; + + return true; +} + +bool LLPluginSharedMemory::unmap(void) +{ + if(mMappedAddress != NULL) + { + UnmapViewOfFile(mMappedAddress); + mMappedAddress = NULL; + } + + return true; +} + +bool LLPluginSharedMemory::close(void) +{ + if(mImpl->mMapFile != NULL) + { + CloseHandle(mImpl->mMapFile); + mImpl->mMapFile = NULL; + } + + return true; +} + +bool LLPluginSharedMemory::unlink(void) +{ + // This is a no-op on Windows. + return true; +} + + +bool LLPluginSharedMemory::create(size_t size) +{ + mName = WIN32_SHARED_MEMORY_PREFIX_STRING; + mName += createName(); + mSize = size; + + mImpl->mMapFile = CreateFileMappingA( + INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // max. object size + mSize, // buffer size + mName.c_str()); // name of mapping object + + if(mImpl->mMapFile == NULL) + { + LL_WARNS("Plugin") << "CreateFileMapping failed: " << GetLastError() << LL_ENDL; + return false; + } + + mNeedsDestroy = true; + + return map(); +} + +bool LLPluginSharedMemory::destroy(void) +{ + unmap(); + close(); + return true; +} + +bool LLPluginSharedMemory::attach(const std::string &name, size_t size) +{ + mName = name; + mSize = size; + + mImpl->mMapFile = OpenFileMappingA( + FILE_MAP_ALL_ACCESS, // read/write access + FALSE, // do not inherit the name + mName.c_str()); // name of mapping object + + if(mImpl->mMapFile == NULL) + { + LL_WARNS("Plugin") << "OpenFileMapping failed: " << GetLastError() << LL_ENDL; + return false; + } + + return map(); +} + +bool LLPluginSharedMemory::detach(void) +{ + unmap(); + close(); + return true; +} + + + +#endif diff --git a/linden/indra/llplugin/llpluginsharedmemory.h b/linden/indra/llplugin/llpluginsharedmemory.h new file mode 100755 index 000000000..669a3e409 --- /dev/null +++ b/linden/indra/llplugin/llpluginsharedmemory.h @@ -0,0 +1,135 @@ +/** + * @file llpluginsharedmemory.h + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LL_LLPLUGINSHAREDMEMORY_H +#define LL_LLPLUGINSHAREDMEMORY_H + +#include "aiaprpool.h" + +class LLPluginSharedMemoryPlatformImpl; + +/** + * @brief LLPluginSharedMemory manages a shared memory segment for use by the LLPlugin API. + * + */ +class LLPluginSharedMemory +{ + LOG_CLASS(LLPluginSharedMemory); +public: + LLPluginSharedMemory(); + ~LLPluginSharedMemory(); + + // Parent will use create/destroy, child will use attach/detach. + // Message transactions will ensure child attaches after parent creates and detaches before parent destroys. + + /** + * Creates a shared memory segment, with a name which is guaranteed to be unique on the host at the current time. Used by parent. + * Message transactions will (? TODO:DOC - should? must?) ensure child attaches after parent creates and detaches before parent destroys. + * + * @param[in] size Shared memory size in TODO:DOC units = bytes?. + * + * @return False for failure, true for success. + */ + bool create(size_t size); + /** + * Destroys a shared memory segment. Used by parent. + * Message transactions will (? TODO:DOC - should? must?) ensure child attaches after parent creates and detaches before parent destroys. + * + * @return True. TODO:DOC - always returns true. Is this the intended behavior? + */ + bool destroy(void); + + /** + * Creates and attaches a name to a shared memory segment. TODO:DOC what's the difference between attach() and create()? + * + * @param[in] name Name to attach to memory segment + * @param[in] size Size of memory segment TODO:DOC in bytes? + * + * @return False on failure, true otherwise. + */ + bool attach(const std::string &name, size_t size); + /** + * Detaches shared memory segment. + * + * @return False on failure, true otherwise. + */ + bool detach(void); + + /** + * Checks if shared memory is mapped to a non-null address. + * + * @return True if memory address is non-null, false otherwise. + */ + bool isMapped(void) const { return (mMappedAddress != NULL); }; + /** + * Get pointer to shared memory. + * + * @return Pointer to shared memory. + */ + void *getMappedAddress(void) const { return mMappedAddress; }; + /** + * Get size of shared memory. + * + * @return Size of shared memory in bytes. TODO:DOC are bytes the correct unit? + */ + size_t getSize(void) const { return mSize; }; + /** + * Get name of shared memory. + * + * @return Name of shared memory. + */ + std::string getName() const { return mName; }; + +private: + bool map(void); + bool unmap(void); + bool close(void); + bool unlink(void); + + AIAPRPool mPool; + std::string mName; + size_t mSize; + void *mMappedAddress; + bool mNeedsDestroy; + + LLPluginSharedMemoryPlatformImpl *mImpl; + + static int sSegmentNumber; + static std::string createName(); + +}; + + + +#endif // LL_LLPLUGINSHAREDMEMORY_H diff --git a/linden/indra/llplugin/slplugin/CMakeLists.txt b/linden/indra/llplugin/slplugin/CMakeLists.txt new file mode 100755 index 000000000..81d929969 --- /dev/null +++ b/linden/indra/llplugin/slplugin/CMakeLists.txt @@ -0,0 +1,82 @@ +project(SLPlugin) + +include(00-Common) +include(LLCommon) +include(LLPlugin) +include(Linking) +include(PluginAPI) +include(LLMessage) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${LLMESSAGE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} +) + +if (DARWIN) + include(CMakeFindFrameworks) + find_library(CARBON_LIBRARY Carbon) + find_library(COCOA_LIBRARY Cocoa) +endif (DARWIN) + + +### SLPlugin + +set(SLPlugin_SOURCE_FILES + slplugin.cpp + ) + +if (DARWIN) + list(APPEND SLPlugin_SOURCE_FILES + slplugin-objc.mm + ) + list(APPEND SLPlugin_HEADER_FILES + slplugin-objc.h + ) +endif (DARWIN) + +set_source_files_properties(${SLPlugin_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +if (SLPlugin_HEADER_FILES) + list(APPEND SLPlugin_SOURCE_FILES ${SLPlugin_HEADER_FILES}) +endif (SLPlugin_HEADER_FILES) + +add_executable(SLPlugin + WIN32 + MACOSX_BUNDLE + ${SLPlugin_SOURCE_FILES} +) + +set_target_properties(SLPlugin + PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist + ) + +target_link_libraries(SLPlugin + ${LLPLUGIN_LIBRARIES} + ${LLMESSAGE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${PLUGIN_API_WINDOWS_LIBRARIES} +) + +add_dependencies(SLPlugin + ${LLPLUGIN_LIBRARIES} + ${LLMESSAGE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + +if (DARWIN) + # Mac version needs to link against Carbon + target_link_libraries(SLPlugin ${CARBON_LIBRARY} ${COCOA_LIBRARY}) + # Make sure the app bundle has a Resources directory (it will get populated by viewer-manifest.py later) + add_custom_command( + TARGET SLPlugin POST_BUILD + COMMAND mkdir + ARGS + -p + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/SLPlugin.app/Contents/Resources + ) +endif (DARWIN) + +#ll_deploy_sharedlibs_command(SLPlugin) diff --git a/linden/indra/llplugin/slplugin/slplugin-objc.h b/linden/indra/llplugin/slplugin/slplugin-objc.h new file mode 100644 index 000000000..42029e45b --- /dev/null +++ b/linden/indra/llplugin/slplugin/slplugin-objc.h @@ -0,0 +1,42 @@ +/** + * @file slplugin-objc.h + * @brief Header file for slplugin-objc.mm. + * + * @cond + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * + * @endcond + */ + + +/* Defined in slplugin-objc.mm: */ +void setupCocoa(); +void createAutoReleasePool(); +void deleteAutoReleasePool(); diff --git a/linden/indra/llplugin/slplugin/slplugin-objc.mm b/linden/indra/llplugin/slplugin/slplugin-objc.mm new file mode 100644 index 000000000..125b26412 --- /dev/null +++ b/linden/indra/llplugin/slplugin/slplugin-objc.mm @@ -0,0 +1,89 @@ +/** + * @file slplugin-objc.mm + * @brief Objective-C++ file for use with the loader shell, so we can use a couple of Cocoa APIs. + * + * @cond + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * + * @endcond + */ + + +#include <AppKit/AppKit.h> + +#include "slplugin-objc.h" + + +void setupCocoa() +{ + static bool inited = false; + + if(!inited) + { + createAutoReleasePool(); + + // The following prevents the Cocoa command line parser from trying to open 'unknown' arguements as documents. + // ie. running './secondlife -set Language fr' would cause a pop-up saying can't open document 'fr' + // when init'ing the Cocoa App window. + [[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"]; + + // This is a bit of voodoo taken from the Apple sample code "CarbonCocoa_PictureCursor": + // http://developer.apple.com/samplecode/CarbonCocoa_PictureCursor/index.html + + // Needed for Carbon based applications which call into Cocoa + NSApplicationLoad(); + + // Must first call [[[NSWindow alloc] init] release] to get the NSWindow machinery set up so that NSCursor can use a window to cache the cursor image + [[[NSWindow alloc] init] release]; + + deleteAutoReleasePool(); + + inited = true; + } +} + +static NSAutoreleasePool *sPool = NULL; + +void createAutoReleasePool() +{ + if(!sPool) + { + sPool = [[NSAutoreleasePool alloc] init]; + } +} + +void deleteAutoReleasePool() +{ + if(sPool) + { + [sPool release]; + sPool = NULL; + } +} diff --git a/linden/indra/llplugin/slplugin/slplugin.cpp b/linden/indra/llplugin/slplugin/slplugin.cpp new file mode 100755 index 000000000..878577bf7 --- /dev/null +++ b/linden/indra/llplugin/slplugin/slplugin.cpp @@ -0,0 +1,405 @@ +/** + * @file slplugin.cpp + * @brief Loader shell for plugins, intended to be launched by the plugin host application, which directly loads a plugin dynamic library. + * + * @cond + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * + * @endcond + */ + + +#include "linden_common.h" + +#include "llpluginprocesschild.h" +#include "llpluginmessage.h" +#include "llerrorcontrol.h" +#include "llapr.h" +#include "llstring.h" + +#if LL_DARWIN + #include <Carbon/Carbon.h> + #include "slplugin-objc.h" +#endif + +#if LL_DARWIN || LL_LINUX + #include <signal.h> +#endif + +/* + On Mac OS, since we call WaitNextEvent, this process will show up in the dock unless we set the LSBackgroundOnly or LSUIElement flag in the Info.plist. + + Normally non-bundled binaries don't have an info.plist file, but it's possible to embed one in the binary by adding this to the linker flags: + + -sectcreate __TEXT __info_plist /path/to/slplugin_info.plist + + which means adding this to the gcc flags: + + -Wl,-sectcreate,__TEXT,__info_plist,/path/to/slplugin_info.plist + + Now that SLPlugin is a bundled app on the Mac, this is no longer necessary (it can just use a regular Info.plist file), but I'm leaving this comment in for posterity. +*/ + +#if LL_DARWIN || LL_LINUX +// Signal handlers to make crashes not show an OS dialog... +static void crash_handler(int sig) +{ + // Just exit cleanly. + // TODO: add our own crash reporting + _exit(1); +} +#endif + +#if LL_WINDOWS +# define WIN32_LEAN_AND_MEAN +# include <winsock2.h> +#include <windows.h> +//////////////////////////////////////////////////////////////////////////////// +// Our exception handler - will probably just exit and the host application +// will miss the heartbeat and log the error in the usual fashion. +LONG WINAPI myWin32ExceptionHandler( struct _EXCEPTION_POINTERS* exception_infop ) +{ + //std::cerr << "This plugin (" << __FILE__ << ") - "; + //std::cerr << "intercepted an unhandled exception and will exit immediately." << std::endl; + + // TODO: replace exception handler before we exit? + return EXCEPTION_EXECUTE_HANDLER; +} + +// Taken from : http://blog.kalmbachnet.de/?postid=75 +// The MSVC 2005 CRT forces the call of the default-debugger (normally Dr.Watson) +// even with the other exception handling code. This (terrifying) piece of code +// patches things so that doesn't happen. +LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter( + LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ) +{ + return NULL; +} + +BOOL PreventSetUnhandledExceptionFilter() +{ +// WARNING: This won't work on 64-bit Windows systems so we turn it off it. +// It should work for any flavor of 32-bit Windows we care about. +// If it's off, sometimes you will see an OS message when a plugin crashes +#ifndef _WIN64 + HMODULE hKernel32 = LoadLibraryA( "kernel32.dll" ); + if ( NULL == hKernel32 ) + return FALSE; + + void *pOrgEntry = GetProcAddress( hKernel32, "SetUnhandledExceptionFilter" ); + if( NULL == pOrgEntry ) + return FALSE; + + unsigned char newJump[ 100 ]; + DWORD dwOrgEntryAddr = (DWORD)pOrgEntry; + dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far + void *pNewFunc = &MyDummySetUnhandledExceptionFilter; + DWORD dwNewEntryAddr = (DWORD) pNewFunc; + DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr; + + newJump[ 0 ] = 0xE9; // JMP absolute + memcpy( &newJump[ 1 ], &dwRelativeAddr, sizeof( pNewFunc ) ); + SIZE_T bytesWritten; + BOOL bRet = WriteProcessMemory( GetCurrentProcess(), pOrgEntry, newJump, sizeof( pNewFunc ) + 1, &bytesWritten ); + return bRet; +#else + return FALSE; +#endif +} + +//////////////////////////////////////////////////////////////////////////////// +// Hook our exception handler and replace the system one +void initExceptionHandler() +{ + LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; + + // save old exception handler in case we need to restore it at the end + prev_filter = SetUnhandledExceptionFilter( myWin32ExceptionHandler ); + PreventSetUnhandledExceptionFilter(); +} + +bool checkExceptionHandler() +{ + bool ok = true; + LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; + prev_filter = SetUnhandledExceptionFilter(myWin32ExceptionHandler); + + PreventSetUnhandledExceptionFilter(); + + if (prev_filter != myWin32ExceptionHandler) + { + LL_WARNS("AppInit") << "Our exception handler (" << (void *)myWin32ExceptionHandler << ") replaced with " << prev_filter << "!" << LL_ENDL; + ok = false; + } + + if (prev_filter == NULL) + { + ok = FALSE; + if (NULL == myWin32ExceptionHandler) + { + LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL; + } + else + { + LL_WARNS("AppInit") << "Our exception handler (" << (void *)myWin32ExceptionHandler << ") replaced with NULL!" << LL_ENDL; + } + } + + return ok; +} +#endif + +// If this application on Windows platform is a console application, a console is always +// created which is bad. Making it a Windows "application" via CMake settings but not +// adding any code to explicitly create windows does the right thing. +#if LL_WINDOWS +int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) +#else +int main(int argc, char **argv) +#endif +{ + // Set up llerror logging + { + LLError::initForApplication("."); + LLError::setDefaultLevel(LLError::LEVEL_INFO); +// LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG); +// LLError::logToFile("slplugin.log"); + } + +#if LL_WINDOWS + if( strlen( lpCmdLine ) == 0 ) + { + LL_ERRS("slplugin") << "usage: " << "SLPlugin" << " launcher_port" << LL_ENDL; + }; + + U32 port = 0; + if(!LLStringUtil::convertToU32(lpCmdLine, port)) + { + LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; + }; + + // Insert our exception handler into the system so this plugin doesn't + // display a crash message if something bad happens. The host app will + // see the missing heartbeat and log appropriately. + initExceptionHandler(); +#elif LL_DARWIN || LL_LINUX + if(argc < 2) + { + LL_ERRS("slplugin") << "usage: " << argv[0] << " launcher_port" << LL_ENDL; + } + + U32 port = 0; + if(!LLStringUtil::convertToU32(argv[1], port)) + { + LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; + } + + // Catch signals that most kinds of crashes will generate, and exit cleanly so the system crash dialog isn't shown. + signal(SIGILL, &crash_handler); // illegal instruction +# if LL_DARWIN + signal(SIGEMT, &crash_handler); // emulate instruction executed +# endif // LL_DARWIN + signal(SIGFPE, &crash_handler); // floating-point exception + signal(SIGBUS, &crash_handler); // bus error + signal(SIGSEGV, &crash_handler); // segmentation violation + signal(SIGSYS, &crash_handler); // non-existent system call invoked +#endif + +#if LL_DARWIN + setupCocoa(); + createAutoReleasePool(); +#endif + + LLPluginProcessChild *plugin = new LLPluginProcessChild(); + + plugin->init(port); + +#if LL_DARWIN + deleteAutoReleasePool(); +#endif + + LLTimer timer; + timer.start(); + +#if LL_WINDOWS + checkExceptionHandler(); +#endif + +#if LL_DARWIN + // If the plugin opens a new window (such as the Flash plugin's fullscreen player), we may need to bring this plugin process to the foreground. + // Use this to track the current frontmost window and bring this process to the front if it changes. + WindowRef front_window = NULL; + WindowGroupRef layer_group = NULL; + int window_hack_state = 0; + CreateWindowGroup(kWindowGroupAttrFixedLevel, &layer_group); + if(layer_group) + { + // Start out with a window layer that's way out in front (fixes the problem with the menubar not getting hidden on first switch to fullscreen youtube) + SetWindowGroupName(layer_group, CFSTR("SLPlugin Layer")); + SetWindowGroupLevel(layer_group, kCGOverlayWindowLevel); + } +#endif + +#if LL_DARWIN + EventTargetRef event_target = GetEventDispatcherTarget(); +#endif + while(!plugin->isDone()) + { +#if LL_DARWIN + createAutoReleasePool(); +#endif + timer.reset(); + plugin->idle(); +#if LL_DARWIN + { + // Some plugins (webkit at least) will want an event loop. This qualifies. + EventRef event; + if(ReceiveNextEvent(0, 0, kEventDurationNoWait, true, &event) == noErr) + { + SendEventToEventTarget (event, event_target); + ReleaseEvent(event); + } + + // Check for a change in this process's frontmost window. + if(FrontWindow() != front_window) + { + ProcessSerialNumber self = { 0, kCurrentProcess }; + ProcessSerialNumber parent = { 0, kNoProcess }; + ProcessSerialNumber front = { 0, kNoProcess }; + Boolean this_is_front_process = false; + Boolean parent_is_front_process = false; + { + // Get this process's parent + ProcessInfoRec info; + info.processInfoLength = sizeof(ProcessInfoRec); + info.processName = NULL; + info.processAppSpec = NULL; + if(GetProcessInformation( &self, &info ) == noErr) + { + parent = info.processLauncher; + } + + // and figure out whether this process or its parent are currently frontmost + if(GetFrontProcess(&front) == noErr) + { + (void) SameProcess(&self, &front, &this_is_front_process); + (void) SameProcess(&parent, &front, &parent_is_front_process); + } + } + + if((FrontWindow() != NULL) && (front_window == NULL)) + { + // Opening the first window + + if(window_hack_state == 0) + { + // Next time through the event loop, lower the window group layer + window_hack_state = 1; + } + + if(layer_group) + { + SetWindowGroup(FrontWindow(), layer_group); + } + + if(parent_is_front_process) + { + // Bring this process's windows to the front. + (void) SetFrontProcess( &self ); + } + + ActivateWindow(FrontWindow(), true); + } + else if((FrontWindow() == NULL) && (front_window != NULL)) + { + // Closing the last window + + if(this_is_front_process) + { + // Try to bring this process's parent to the front + (void) SetFrontProcess(&parent); + } + } + else if(window_hack_state == 1) + { + if(layer_group) + { + // Set the window group level back to something less extreme + SetWindowGroupLevel(layer_group, kCGNormalWindowLevel); + } + window_hack_state = 2; + } + + front_window = FrontWindow(); + + } + } +#endif + F64 elapsed = timer.getElapsedTimeF64(); + F64 remaining = plugin->getSleepTime() - elapsed; + + if(remaining <= 0.0f) + { + // We've already used our full allotment. +// LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, not sleeping" << LL_ENDL; + + // Still need to service the network... + plugin->pump(); + } + else + { + +// LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, sleeping for " << remaining * 1000.0f << " ms" << LL_ENDL; +// timer.reset(); + + // This also services the network as needed. + plugin->sleep(remaining); + +// LL_INFOS("slplugin") << "slept for "<< timer.getElapsedTimeF64() * 1000.0f << " ms" << LL_ENDL; + } + +#if LL_WINDOWS + // More agressive checking of interfering exception handlers. + // Doesn't appear to be required so far - even for plugins + // that do crash with a single call to the intercept + // exception handler such as QuickTime. + //checkExceptionHandler(); +#endif + +#if LL_DARWIN + deleteAutoReleasePool(); +#endif + } + + delete plugin; + + return 0; +} + diff --git a/linden/indra/llplugin/slplugin/slplugin_info.plist b/linden/indra/llplugin/slplugin/slplugin_info.plist new file mode 100755 index 000000000..c4597380e --- /dev/null +++ b/linden/indra/llplugin/slplugin/slplugin_info.plist @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>LSUIElement</key> + <string>1</string> +</dict> +</plist> diff --git a/linden/indra/llprimitive/CMakeLists.txt b/linden/indra/llprimitive/CMakeLists.txt old mode 100644 new mode 100755 index 5dc4c701a..e7ee81141 --- a/linden/indra/llprimitive/CMakeLists.txt +++ b/linden/indra/llprimitive/CMakeLists.txt @@ -17,12 +17,15 @@ include_directories( set(llprimitive_SOURCE_FILES llmaterialtable.cpp + llmediaentry.cpp llprimitive.cpp + llprimtexturelist.cpp lltextureanim.cpp lltextureentry.cpp lltreeparams.cpp llvolumemessage.cpp llvolumexml.cpp + material_codes.cpp ) set(llprimitive_HEADER_FILES @@ -30,7 +33,9 @@ set(llprimitive_HEADER_FILES legacy_object_types.h llmaterialtable.h + llmediaentry.h llprimitive.h + llprimtexturelist.h lltextureanim.h lltextureentry.h lltreeparams.h @@ -47,3 +52,10 @@ set_source_files_properties(${llprimitive_HEADER_FILES} list(APPEND llprimitive_SOURCE_FILES ${llprimitive_HEADER_FILES}) add_library (llprimitive ${llprimitive_SOURCE_FILES}) + +#add unit tests +INCLUDE(LLAddBuildTest) +SET(llprimitive_TEST_SOURCE_FILES + llmediaentry.cpp + ) +#LL_ADD_PROJECT_UNIT_TESTS(llprimitive "${llprimitive_TEST_SOURCE_FILES}") diff --git a/linden/indra/llprimitive/llmaterialtable.cpp b/linden/indra/llprimitive/llmaterialtable.cpp old mode 100644 new mode 100755 index 92eef96cf..7dd764e77 --- a/linden/indra/llprimitive/llmaterialtable.cpp +++ b/linden/indra/llprimitive/llmaterialtable.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -102,6 +102,9 @@ F32 const LLMaterialTable::DEFAULT_FRICTION = 0.5f; F32 const LLMaterialTable::DEFAULT_RESTITUTION = 0.4f; LLMaterialTable::LLMaterialTable() + : mCollisionSoundMatrix(NULL), + mSlidingSoundMatrix(NULL), + mRollingSoundMatrix(NULL) { } @@ -134,6 +137,17 @@ LLMaterialTable::~LLMaterialTable() mMaterialInfoList.clear(); } +void LLMaterialTable::initTableTransNames(std::map<std::string, std::string> namemap) +{ + for (info_list_t::iterator iter = mMaterialInfoList.begin(); + iter != mMaterialInfoList.end(); ++iter) + { + LLMaterialInfo *infop = *iter; + std::string name = infop->mName; + infop->mName = namemap[name]; + } +} + void LLMaterialTable::initBasicTable() { // *TODO: Translate diff --git a/linden/indra/llprimitive/llmaterialtable.h b/linden/indra/llprimitive/llmaterialtable.h old mode 100644 new mode 100755 index ca9017abd..7950c406b --- a/linden/indra/llprimitive/llmaterialtable.h +++ b/linden/indra/llprimitive/llmaterialtable.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -38,6 +38,8 @@ #include <list> +class LLMaterialInfo; + const U32 LLMATERIAL_INFO_NAME_LENGTH = 256; // We've moved toward more reasonable mass values for the Havok4 engine. @@ -64,45 +66,6 @@ const F32 LEGACY_DEFAULT_OBJECT_DENSITY = 10.0f; const F32 DEFAULT_AVATAR_DENSITY = 445.3f; // was 444.24f; -class LLMaterialInfo -{ -public: - U8 mMCode; - std::string mName; - LLUUID mDefaultTextureID; - LLUUID mShatterSoundID; - F32 mDensity; // kg/m^3 - F32 mFriction; - F32 mRestitution; - - // damage and energy constants - F32 mHPModifier; // modifier on mass based HP total - F32 mDamageModifier; // modifier on KE based damage - F32 mEPModifier; // modifier on mass based EP total - - LLMaterialInfo(U8 mcode, const std::string& name, const LLUUID &uuid) - { - init(mcode,name,uuid); - }; - - void init(U8 mcode, const std::string& name, const LLUUID &uuid) - { - mDensity = 1000.f; // default to 1000.0 (water) - mHPModifier = 1.f; - mDamageModifier = 1.f; - mEPModifier = 1.f; - - mMCode = mcode; - mName = name; - mDefaultTextureID = uuid; - }; - - ~LLMaterialInfo() - { - }; - -}; - class LLMaterialTable { public: @@ -147,6 +110,8 @@ class LLMaterialTable void initBasicTable(); + void initTableTransNames(std::map<std::string, std::string> namemap); + BOOL add(U8 mcode, const std::string& name, const LLUUID &uuid); BOOL addCollisionSound(U8 mcode, U8 mcode2, const LLUUID &uuid); BOOL addSlidingSound(U8 mcode, U8 mcode2, const LLUUID &uuid); @@ -183,5 +148,47 @@ class LLMaterialTable static LLMaterialTable basic; }; + +class LLMaterialInfo +{ +public: + U8 mMCode; + std::string mName; + LLUUID mDefaultTextureID; + LLUUID mShatterSoundID; + F32 mDensity; // kg/m^3 + F32 mFriction; + F32 mRestitution; + + // damage and energy constants + F32 mHPModifier; // modifier on mass based HP total + F32 mDamageModifier; // modifier on KE based damage + F32 mEPModifier; // modifier on mass based EP total + + LLMaterialInfo(U8 mcode, const std::string& name, const LLUUID &uuid) + { + init(mcode,name,uuid); + }; + + void init(U8 mcode, const std::string& name, const LLUUID &uuid) + { + mDensity = 1000.f; // default to 1000.0 (water) + mFriction = LLMaterialTable::DEFAULT_FRICTION; + mRestitution = LLMaterialTable::DEFAULT_RESTITUTION; + mHPModifier = 1.f; + mDamageModifier = 1.f; + mEPModifier = 1.f; + + mMCode = mcode; + mName = name; + mDefaultTextureID = uuid; + }; + + ~LLMaterialInfo() + { + }; + +}; + #endif diff --git a/linden/indra/llprimitive/llmediaentry.cpp b/linden/indra/llprimitive/llmediaentry.cpp new file mode 100755 index 000000000..e4b31e221 --- /dev/null +++ b/linden/indra/llprimitive/llmediaentry.cpp @@ -0,0 +1,602 @@ +/** + * @file llmediaentry.cpp + * @brief This is a single instance of media data related to the face of a prim + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llmediaentry.h" +#include "lllslconstants.h" + +#include <boost/regex.hpp> + +// LLSD key defines +// DO NOT REORDER OR REMOVE THESE! + +// Some LLSD keys. Do not change! +#define MEDIA_ALT_IMAGE_ENABLE_KEY_STR "alt_image_enable" +#define MEDIA_CONTROLS_KEY_STR "controls" +#define MEDIA_CURRENT_URL_KEY_STR "current_url" +#define MEDIA_HOME_URL_KEY_STR "home_url" +#define MEDIA_AUTO_LOOP_KEY_STR "auto_loop" +#define MEDIA_AUTO_PLAY_KEY_STR "auto_play" +#define MEDIA_AUTO_SCALE_KEY_STR "auto_scale" +#define MEDIA_AUTO_ZOOM_KEY_STR "auto_zoom" +#define MEDIA_FIRST_CLICK_INTERACT_KEY_STR "first_click_interact" +#define MEDIA_WIDTH_PIXELS_KEY_STR "width_pixels" +#define MEDIA_HEIGHT_PIXELS_KEY_STR "height_pixels" + +// "security" fields +#define MEDIA_WHITELIST_ENABLE_KEY_STR "whitelist_enable" +#define MEDIA_WHITELIST_KEY_STR "whitelist" + +// "permissions" fields +#define MEDIA_PERMS_INTERACT_KEY_STR "perms_interact" +#define MEDIA_PERMS_CONTROL_KEY_STR "perms_control" + +// "general" fields +const char* LLMediaEntry::ALT_IMAGE_ENABLE_KEY = MEDIA_ALT_IMAGE_ENABLE_KEY_STR; +const char* LLMediaEntry::CONTROLS_KEY = MEDIA_CONTROLS_KEY_STR; +const char* LLMediaEntry::CURRENT_URL_KEY = MEDIA_CURRENT_URL_KEY_STR; +const char* LLMediaEntry::HOME_URL_KEY = MEDIA_HOME_URL_KEY_STR; +const char* LLMediaEntry::AUTO_LOOP_KEY = MEDIA_AUTO_LOOP_KEY_STR; +const char* LLMediaEntry::AUTO_PLAY_KEY = MEDIA_AUTO_PLAY_KEY_STR; +const char* LLMediaEntry::AUTO_SCALE_KEY = MEDIA_AUTO_SCALE_KEY_STR; +const char* LLMediaEntry::AUTO_ZOOM_KEY = MEDIA_AUTO_ZOOM_KEY_STR; +const char* LLMediaEntry::FIRST_CLICK_INTERACT_KEY = MEDIA_FIRST_CLICK_INTERACT_KEY_STR; +const char* LLMediaEntry::WIDTH_PIXELS_KEY = MEDIA_WIDTH_PIXELS_KEY_STR; +const char* LLMediaEntry::HEIGHT_PIXELS_KEY = MEDIA_HEIGHT_PIXELS_KEY_STR; + +// "security" fields +const char* LLMediaEntry::WHITELIST_ENABLE_KEY = MEDIA_WHITELIST_ENABLE_KEY_STR; +const char* LLMediaEntry::WHITELIST_KEY = MEDIA_WHITELIST_KEY_STR; + +// "permissions" fields +const char* LLMediaEntry::PERMS_INTERACT_KEY = MEDIA_PERMS_INTERACT_KEY_STR; +const char* LLMediaEntry::PERMS_CONTROL_KEY = MEDIA_PERMS_CONTROL_KEY_STR; + +#define DEFAULT_URL_PREFIX "http://" + +// Constructor(s) +LLMediaEntry::LLMediaEntry() : + mAltImageEnable(false), + mControls(STANDARD), + mCurrentURL(""), + mHomeURL(""), + mAutoLoop(false), + mAutoPlay(false), + mAutoScale(false), + mAutoZoom(false), + mFirstClickInteract(false), + mWidthPixels(0), + mHeightPixels(0), + mWhiteListEnable(false), + // mWhiteList + mPermsInteract(PERM_ALL), + mPermsControl(PERM_ALL), + mMediaIDp(NULL) +{ +} + +LLMediaEntry::LLMediaEntry(const LLMediaEntry &rhs) : + mMediaIDp(NULL) +{ + // "general" fields + mAltImageEnable = rhs.mAltImageEnable; + mControls = rhs.mControls; + mCurrentURL = rhs.mCurrentURL; + mHomeURL = rhs.mHomeURL; + mAutoLoop = rhs.mAutoLoop; + mAutoPlay = rhs.mAutoPlay; + mAutoScale = rhs.mAutoScale; + mAutoZoom = rhs.mAutoZoom; + mFirstClickInteract = rhs.mFirstClickInteract; + mWidthPixels = rhs.mWidthPixels; + mHeightPixels = rhs.mHeightPixels; + + // "security" fields + mWhiteListEnable = rhs.mWhiteListEnable; + mWhiteList = rhs.mWhiteList; + + // "permissions" fields + mPermsInteract = rhs.mPermsInteract; + mPermsControl = rhs.mPermsControl; +} + +LLMediaEntry::~LLMediaEntry() +{ + if (NULL != mMediaIDp) + { + delete mMediaIDp; + } +} + +LLSD LLMediaEntry::asLLSD() const +{ + LLSD sd; + asLLSD(sd); + return sd; +} + +// +// LLSD functions +// +void LLMediaEntry::asLLSD(LLSD& sd) const +{ + // "general" fields + sd[ALT_IMAGE_ENABLE_KEY] = mAltImageEnable; + sd[CONTROLS_KEY] = (LLSD::Integer)mControls; + sd[CURRENT_URL_KEY] = mCurrentURL; + sd[HOME_URL_KEY] = mHomeURL; + sd[AUTO_LOOP_KEY] = mAutoLoop; + sd[AUTO_PLAY_KEY] = mAutoPlay; + sd[AUTO_SCALE_KEY] = mAutoScale; + sd[AUTO_ZOOM_KEY] = mAutoZoom; + sd[FIRST_CLICK_INTERACT_KEY] = mFirstClickInteract; + sd[WIDTH_PIXELS_KEY] = mWidthPixels; + sd[HEIGHT_PIXELS_KEY] = mHeightPixels; + + // "security" fields + sd[WHITELIST_ENABLE_KEY] = mWhiteListEnable; + sd.erase(WHITELIST_KEY); + for (U32 i=0; i<mWhiteList.size(); i++) + { + sd[WHITELIST_KEY].append(mWhiteList[i]); + } + + // "permissions" fields + sd[PERMS_INTERACT_KEY] = mPermsInteract; + sd[PERMS_CONTROL_KEY] = mPermsControl; +} + +// static +bool LLMediaEntry::checkLLSD(const LLSD& sd) +{ + if (sd.isUndefined()) return true; + LLMediaEntry temp; + return temp.fromLLSDInternal(sd, true); +} + +void LLMediaEntry::fromLLSD(const LLSD& sd) +{ + (void)fromLLSDInternal(sd, true); +} + +void LLMediaEntry::mergeFromLLSD(const LLSD& sd) +{ + (void)fromLLSDInternal(sd, false); +} + +// *NOTE: returns true if NO failures to set occurred, false otherwise. +// However, be aware that if a failure to set does occur, it does +// not stop setting fields from the LLSD! +bool LLMediaEntry::fromLLSDInternal(const LLSD& sd, bool overwrite) +{ + // *HACK: we sort of cheat here and assume that status is a + // bit field. We "or" into status and instead of returning + // it, we return whether it finishes off as LSL_STATUS_OK or not. + U32 status = LSL_STATUS_OK; + + // "general" fields + if ( overwrite || sd.has(ALT_IMAGE_ENABLE_KEY) ) + { + status |= setAltImageEnable( sd[ALT_IMAGE_ENABLE_KEY] ); + } + if ( overwrite || sd.has(CONTROLS_KEY) ) + { + status |= setControls( (MediaControls)(LLSD::Integer)sd[CONTROLS_KEY] ); + } + if ( overwrite || sd.has(CURRENT_URL_KEY) ) + { + // Don't check whitelist + status |= setCurrentURLInternal( sd[CURRENT_URL_KEY], false ); + } + if ( overwrite || sd.has(HOME_URL_KEY) ) + { + status |= setHomeURL( sd[HOME_URL_KEY] ); + } + if ( overwrite || sd.has(AUTO_LOOP_KEY) ) + { + status |= setAutoLoop( sd[AUTO_LOOP_KEY] ); + } + if ( overwrite || sd.has(AUTO_PLAY_KEY) ) + { + status |= setAutoPlay( sd[AUTO_PLAY_KEY] ); + } + if ( overwrite || sd.has(AUTO_SCALE_KEY) ) + { + status |= setAutoScale( sd[AUTO_SCALE_KEY] ); + } + if ( overwrite || sd.has(AUTO_ZOOM_KEY) ) + { + status |= setAutoZoom( sd[AUTO_ZOOM_KEY] ); + } + if ( overwrite || sd.has(FIRST_CLICK_INTERACT_KEY) ) + { + status |= setFirstClickInteract( sd[FIRST_CLICK_INTERACT_KEY] ); + } + if ( overwrite || sd.has(WIDTH_PIXELS_KEY) ) + { + status |= setWidthPixels( (LLSD::Integer)sd[WIDTH_PIXELS_KEY] ); + } + if ( overwrite || sd.has(HEIGHT_PIXELS_KEY) ) + { + status |= setHeightPixels( (LLSD::Integer)sd[HEIGHT_PIXELS_KEY] ); + } + + // "security" fields + if ( overwrite || sd.has(WHITELIST_ENABLE_KEY) ) + { + status |= setWhiteListEnable( sd[WHITELIST_ENABLE_KEY] ); + } + if ( overwrite || sd.has(WHITELIST_KEY) ) + { + status |= setWhiteList( sd[WHITELIST_KEY] ); + } + + // "permissions" fields + if ( overwrite || sd.has(PERMS_INTERACT_KEY) ) + { + status |= setPermsInteract( 0xff & (LLSD::Integer)sd[PERMS_INTERACT_KEY] ); + } + if ( overwrite || sd.has(PERMS_CONTROL_KEY) ) + { + status |= setPermsControl( 0xff & (LLSD::Integer)sd[PERMS_CONTROL_KEY] ); + } + + return LSL_STATUS_OK == status; +} + +LLMediaEntry& LLMediaEntry::operator=(const LLMediaEntry &rhs) +{ + if (this != &rhs) + { + // "general" fields + mAltImageEnable = rhs.mAltImageEnable; + mControls = rhs.mControls; + mCurrentURL = rhs.mCurrentURL; + mHomeURL = rhs.mHomeURL; + mAutoLoop = rhs.mAutoLoop; + mAutoPlay = rhs.mAutoPlay; + mAutoScale = rhs.mAutoScale; + mAutoZoom = rhs.mAutoZoom; + mFirstClickInteract = rhs.mFirstClickInteract; + mWidthPixels = rhs.mWidthPixels; + mHeightPixels = rhs.mHeightPixels; + + // "security" fields + mWhiteListEnable = rhs.mWhiteListEnable; + mWhiteList = rhs.mWhiteList; + + // "permissions" fields + mPermsInteract = rhs.mPermsInteract; + mPermsControl = rhs.mPermsControl; + } + + return *this; +} + +bool LLMediaEntry::operator==(const LLMediaEntry &rhs) const +{ + return ( + // "general" fields + mAltImageEnable == rhs.mAltImageEnable && + mControls == rhs.mControls && + mCurrentURL == rhs.mCurrentURL && + mHomeURL == rhs.mHomeURL && + mAutoLoop == rhs.mAutoLoop && + mAutoPlay == rhs.mAutoPlay && + mAutoScale == rhs.mAutoScale && + mAutoZoom == rhs.mAutoZoom && + mFirstClickInteract == rhs.mFirstClickInteract && + mWidthPixels == rhs.mWidthPixels && + mHeightPixels == rhs.mHeightPixels && + + // "security" fields + mWhiteListEnable == rhs.mWhiteListEnable && + mWhiteList == rhs.mWhiteList && + + // "permissions" fields + mPermsInteract == rhs.mPermsInteract && + mPermsControl == rhs.mPermsControl + + ); +} + +bool LLMediaEntry::operator!=(const LLMediaEntry &rhs) const +{ + return ( + // "general" fields + mAltImageEnable != rhs.mAltImageEnable || + mControls != rhs.mControls || + mCurrentURL != rhs.mCurrentURL || + mHomeURL != rhs.mHomeURL || + mAutoLoop != rhs.mAutoLoop || + mAutoPlay != rhs.mAutoPlay || + mAutoScale != rhs.mAutoScale || + mAutoZoom != rhs.mAutoZoom || + mFirstClickInteract != rhs.mFirstClickInteract || + mWidthPixels != rhs.mWidthPixels || + mHeightPixels != rhs.mHeightPixels || + + // "security" fields + mWhiteListEnable != rhs.mWhiteListEnable || + mWhiteList != rhs.mWhiteList || + + // "permissions" fields + mPermsInteract != rhs.mPermsInteract || + mPermsControl != rhs.mPermsControl + + ); +} + +U32 LLMediaEntry::setWhiteList( const std::vector<std::string> &whitelist ) +{ + // *NOTE: This code is VERY similar to the setWhitelist below. + // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER! + U32 size = 0; + U32 count = 0; + // First count to make sure the size constraint is not violated + std::vector<std::string>::const_iterator iter = whitelist.begin(); + std::vector<std::string>::const_iterator end = whitelist.end(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter); + size += entry.length() + 1; // Include one for \0 + count ++; + if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT) + { + return LSL_STATUS_BOUNDS_ERROR; + } + } + // Next clear the vector + mWhiteList.clear(); + // Then re-iterate and copy entries + iter = whitelist.begin(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter); + mWhiteList.push_back(entry); + } + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setWhiteList( const LLSD &whitelist ) +{ + // If whitelist is undef, the whitelist is cleared + if (whitelist.isUndefined()) + { + mWhiteList.clear(); + return LSL_STATUS_OK; + } + + // However, if the whitelist is an empty array, erase it. + if (whitelist.isArray()) + { + // *NOTE: This code is VERY similar to the setWhitelist above. + // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER! + U32 size = 0; + U32 count = 0; + // First check to make sure the size and count constraints are not violated + LLSD::array_const_iterator iter = whitelist.beginArray(); + LLSD::array_const_iterator end = whitelist.endArray(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter).asString(); + size += entry.length() + 1; // Include one for \0 + count ++; + if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT) + { + return LSL_STATUS_BOUNDS_ERROR; + } + } + // Next clear the vector + mWhiteList.clear(); + // Then re-iterate and copy entries + iter = whitelist.beginArray(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter).asString(); + mWhiteList.push_back(entry); + } + return LSL_STATUS_OK; + } + else + { + return LSL_STATUS_MALFORMED_PARAMS; + } +} + + +static void prefix_with(std::string &str, const char *chars, const char *prefix) +{ + // Given string 'str', prefix all instances of any character in 'chars' + // with 'prefix' + size_t found = str.find_first_of(chars); + size_t prefix_len = strlen(prefix); + while (found != std::string::npos) + { + str.insert(found, prefix, prefix_len); + found = str.find_first_of(chars, found+prefix_len+1); + } +} + +static bool pattern_match(const std::string &candidate_str, const std::string &pattern) +{ + // If the pattern is empty, it matches + if (pattern.empty()) return true; + + // 'pattern' is a glob pattern, we only accept '*' chars + // copy it + std::string expression = pattern; + + // Escape perl's regexp chars with a backslash, except all "*" chars + prefix_with(expression, ".[{()\\+?|^$", "\\"); + prefix_with(expression, "*", "."); + + // case-insensitive matching: + boost::regex regexp(expression, boost::regex::perl|boost::regex::icase); + return boost::regex_match(candidate_str, regexp); +} + +bool LLMediaEntry::checkCandidateUrl(const std::string& url) const +{ + if (getWhiteListEnable()) + { + return checkUrlAgainstWhitelist(url, getWhiteList()); + } + else + { + return true; + } +} + +// static +bool LLMediaEntry::checkUrlAgainstWhitelist(const std::string& url, + const std::vector<std::string> &whitelist) +{ + bool passes = true; + // *NOTE: no entries? Don't check + if (whitelist.size() > 0) + { + passes = false; + + // Case insensitive: the reason why we toUpper both this and the + // filter + std::string candidate_url = url; + // Use lluri to see if there is a path part in the candidate URL. No path? Assume "/" + LLURI candidate_uri(candidate_url); + std::vector<std::string>::const_iterator iter = whitelist.begin(); + std::vector<std::string>::const_iterator end = whitelist.end(); + for ( ; iter < end; ++iter ) + { + std::string filter = *iter; + + LLURI filter_uri(filter); + bool scheme_passes = pattern_match( candidate_uri.scheme(), filter_uri.scheme() ); + if (filter_uri.scheme().empty()) + { + filter_uri = LLURI(DEFAULT_URL_PREFIX + filter); + } + bool authority_passes = pattern_match( candidate_uri.authority(), filter_uri.authority() ); + bool path_passes = pattern_match( candidate_uri.escapedPath(), filter_uri.escapedPath() ); + + if (scheme_passes && authority_passes && path_passes) + { + passes = true; + break; + } + } + } + return passes; +} + +U32 LLMediaEntry::setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit ) +{ + if ( value.length() > limit ) + { + return LSL_STATUS_BOUNDS_ERROR; + } + else + { + field = value; + return LSL_STATUS_OK; + } +} + +U32 LLMediaEntry::setControls(LLMediaEntry::MediaControls controls) +{ + if (controls == STANDARD || + controls == MINI) + { + mControls = controls; + return LSL_STATUS_OK; + } + return LSL_STATUS_BOUNDS_ERROR; +} + +U32 LLMediaEntry::setPermsInteract( U8 val ) +{ + mPermsInteract = val & PERM_MASK; + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setPermsControl( U8 val ) +{ + mPermsControl = val & PERM_MASK; + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setCurrentURL(const std::string& current_url) +{ + return setCurrentURLInternal( current_url, true ); +} + +U32 LLMediaEntry::setCurrentURLInternal(const std::string& current_url, bool check_whitelist) +{ + if ( ! check_whitelist || checkCandidateUrl(current_url)) + { + return setStringFieldWithLimit( mCurrentURL, current_url, MAX_URL_LENGTH ); + } + else + { + return LSL_STATUS_WHITELIST_FAILED; + } +} + +U32 LLMediaEntry::setHomeURL(const std::string& home_url) +{ + return setStringFieldWithLimit( mHomeURL, home_url, MAX_URL_LENGTH ); +} + +U32 LLMediaEntry::setWidthPixels(U16 width) +{ + if (width > MAX_WIDTH_PIXELS) return LSL_STATUS_BOUNDS_ERROR; + mWidthPixels = width; + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setHeightPixels(U16 height) +{ + if (height > MAX_HEIGHT_PIXELS) return LSL_STATUS_BOUNDS_ERROR; + mHeightPixels = height; + return LSL_STATUS_OK; +} + +const LLUUID &LLMediaEntry::getMediaID() const +{ + // Lazily generate media ID + if (NULL == mMediaIDp) + { + mMediaIDp = new LLUUID(); + mMediaIDp->generate(); + } + return *mMediaIDp; +} + diff --git a/linden/indra/llprimitive/llmediaentry.h b/linden/indra/llprimitive/llmediaentry.h new file mode 100755 index 000000000..ca52e6e23 --- /dev/null +++ b/linden/indra/llprimitive/llmediaentry.h @@ -0,0 +1,228 @@ +/** + * @file llmediaentry.h + * @brief This is a single instance of media data related to the face of a prim + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLMEDIAENTRY_H +#define LL_LLMEDIAENTRY_H + +#include "llsd.h" +#include "llstring.h" + +// For return values of set* +#include "lllslconstants.h" + +class LLMediaEntry +{ +public: + enum MediaControls { + STANDARD = 0, + MINI + }; + + // Constructors + LLMediaEntry(); + LLMediaEntry(const LLMediaEntry &rhs); + + LLMediaEntry &operator=(const LLMediaEntry &rhs); + virtual ~LLMediaEntry(); + + bool operator==(const LLMediaEntry &rhs) const; + bool operator!=(const LLMediaEntry &rhs) const; + + // Render as LLSD + LLSD asLLSD() const; + void asLLSD(LLSD& sd) const; + operator LLSD() const { return asLLSD(); } + // Returns false iff the given LLSD contains fields that violate any bounds + // limits. + static bool checkLLSD(const LLSD& sd); + // This doesn't merge, it overwrites the data, so will use + // LLSD defaults if need be. Note: does not check limits! + // Use checkLLSD() above first to ensure the LLSD is valid. + void fromLLSD(const LLSD& sd); + // This merges data from the incoming LLSD into our fields. + // Note that it also does NOT check limits! Use checkLLSD() above first. + void mergeFromLLSD(const LLSD& sd); + + // "general" fields + bool getAltImageEnable() const { return mAltImageEnable; } + MediaControls getControls() const { return mControls; } + std::string getCurrentURL() const { return mCurrentURL; } + std::string getHomeURL() const { return mHomeURL; } + bool getAutoLoop() const { return mAutoLoop; } + bool getAutoPlay() const { return mAutoPlay; } + bool getAutoScale() const { return mAutoScale; } + bool getAutoZoom() const { return mAutoZoom; } + bool getFirstClickInteract() const { return mFirstClickInteract; } + U16 getWidthPixels() const { return mWidthPixels; } + U16 getHeightPixels() const { return mHeightPixels; } + + // "security" fields + bool getWhiteListEnable() const { return mWhiteListEnable; } + const std::vector<std::string> &getWhiteList() const { return mWhiteList; } + + // "permissions" fields + U8 getPermsInteract() const { return mPermsInteract; } + U8 getPermsControl() const { return mPermsControl; } + + // Setters. Those that return a U32 return a status error code + // See lllslconstants.h + + // "general" fields + U32 setAltImageEnable(bool alt_image_enable) { mAltImageEnable = alt_image_enable; return LSL_STATUS_OK; } + U32 setControls(MediaControls controls); + U32 setCurrentURL(const std::string& current_url); + U32 setHomeURL(const std::string& home_url); + U32 setAutoLoop(bool auto_loop) { mAutoLoop = auto_loop; return LSL_STATUS_OK; } + U32 setAutoPlay(bool auto_play) { mAutoPlay = auto_play; return LSL_STATUS_OK; } + U32 setAutoScale(bool auto_scale) { mAutoScale = auto_scale; return LSL_STATUS_OK; } + U32 setAutoZoom(bool auto_zoom) { mAutoZoom = auto_zoom; return LSL_STATUS_OK; } + U32 setFirstClickInteract(bool first_click) { mFirstClickInteract = first_click; return LSL_STATUS_OK; } + U32 setWidthPixels(U16 width); + U32 setHeightPixels(U16 height); + + // "security" fields + U32 setWhiteListEnable( bool whitelist_enable ) { mWhiteListEnable = whitelist_enable; return LSL_STATUS_OK; } + U32 setWhiteList( const std::vector<std::string> &whitelist ); + U32 setWhiteList( const LLSD &whitelist ); // takes an LLSD array + + // "permissions" fields + U32 setPermsInteract( U8 val ); + U32 setPermsControl( U8 val ); + + const LLUUID& getMediaID() const; + + // Helper function to check a candidate URL against the whitelist + // Returns true iff candidate URL passes (or if there is no whitelist), false otherwise + bool checkCandidateUrl(const std::string& url) const; + +public: + // Static function to check a URL against a whitelist + // Returns true iff url passes the given whitelist + static bool checkUrlAgainstWhitelist(const std::string &url, + const std::vector<std::string> &whitelist); + +public: + // LLSD key defines + // "general" fields + static const char* ALT_IMAGE_ENABLE_KEY; + static const char* CONTROLS_KEY; + static const char* CURRENT_URL_KEY; + static const char* HOME_URL_KEY; + static const char* AUTO_LOOP_KEY; + static const char* AUTO_PLAY_KEY; + static const char* AUTO_SCALE_KEY; + static const char* AUTO_ZOOM_KEY; + static const char* FIRST_CLICK_INTERACT_KEY; + static const char* WIDTH_PIXELS_KEY; + static const char* HEIGHT_PIXELS_KEY; + + // "security" fields + static const char* WHITELIST_ENABLE_KEY; + static const char* WHITELIST_KEY; + + // "permissions" fields + static const char* PERMS_INTERACT_KEY; + static const char* PERMS_CONTROL_KEY; + + // Field enumerations & constants + + // *NOTE: DO NOT change the order of these, and do not insert values + // in the middle! + // Add values to the end, and make sure to change PARAM_MAX_ID! + enum Fields { + ALT_IMAGE_ENABLE_ID = 0, + CONTROLS_ID = 1, + CURRENT_URL_ID = 2, + HOME_URL_ID = 3, + AUTO_LOOP_ID = 4, + AUTO_PLAY_ID = 5, + AUTO_SCALE_ID = 6, + AUTO_ZOOM_ID = 7, + FIRST_CLICK_INTERACT_ID = 8, + WIDTH_PIXELS_ID = 9, + HEIGHT_PIXELS_ID = 10, + WHITELIST_ENABLE_ID = 11, + WHITELIST_ID = 12, + PERMS_INTERACT_ID = 13, + PERMS_CONTROL_ID = 14, + PARAM_MAX_ID = PERMS_CONTROL_ID + }; + + // "permissions" values + // (e.g. (PERM_OWNER | PERM_GROUP) sets permissions on for OWNER and GROUP + static const U8 PERM_NONE = 0x0; + static const U8 PERM_OWNER = 0x1; + static const U8 PERM_GROUP = 0x2; + static const U8 PERM_ANYONE = 0x4; + static const U8 PERM_ALL = PERM_OWNER|PERM_GROUP|PERM_ANYONE; + static const U8 PERM_MASK = PERM_OWNER|PERM_GROUP|PERM_ANYONE; + + // Limits (in bytes) + static const U32 MAX_URL_LENGTH = 1024; + static const U32 MAX_WHITELIST_SIZE = 1024; + static const U32 MAX_WHITELIST_COUNT = 64; + static const U16 MAX_WIDTH_PIXELS = 2048; + static const U16 MAX_HEIGHT_PIXELS = 2048; + +private: + + U32 setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit ); + U32 setCurrentURLInternal( const std::string &url, bool check_whitelist); + bool fromLLSDInternal(const LLSD &sd, bool overwrite); + +private: + // "general" fields + bool mAltImageEnable; + MediaControls mControls; + std::string mCurrentURL; + std::string mHomeURL; + bool mAutoLoop; + bool mAutoPlay; + bool mAutoScale; + bool mAutoZoom; + bool mFirstClickInteract; + U16 mWidthPixels; + U16 mHeightPixels; + + // "security" fields + bool mWhiteListEnable; + std::vector<std::string> mWhiteList; + + // "permissions" fields + U8 mPermsInteract; + U8 mPermsControl; + + mutable LLUUID *mMediaIDp; // temporary id assigned to media on the viewer +}; + +#endif + diff --git a/linden/indra/llprimitive/llprimitive.cpp b/linden/indra/llprimitive/llprimitive.cpp old mode 100644 new mode 100755 index f1b7522ca..0ad9f795a --- a/linden/indra/llprimitive/llprimitive.cpp +++ b/linden/indra/llprimitive/llprimitive.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -43,7 +43,8 @@ #include "llvolumemgr.h" #include "llstring.h" #include "lldatapacker.h" -#include "llsdutil.h" +#include "llsdutil.h"//_math.h" +#include "llprimtexturelist.h" /** * exported constants @@ -111,6 +112,7 @@ const F32 FLEXIBLE_OBJECT_DEFAULT_LENGTH = 1.0f; const BOOL FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE = FALSE; const BOOL FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE = FALSE; +const S32 MAX_FACE_BITS = 9; const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; // old inverted texture: "7595d345-a24c-e7ef-f0bd-78793792133e"; @@ -129,7 +131,7 @@ void LLPrimitive::setVolumeManager( LLVolumeMgr* volume_manager ) { if ( !volume_manager || sVolumeManager ) { - llerrs << "Unable to set LLPrimitive::sVolumeManager to NULL" << llendl; + llerrs << "LLPrimitive::sVolumeManager attempting to be set to NULL or it already has been set." << llendl; } sVolumeManager = volume_manager; } @@ -150,7 +152,9 @@ bool LLPrimitive::cleanupVolumeManager() //=============================================================== LLPrimitive::LLPrimitive() -: mMiscFlags(0) +: mTextureList(), + mNumTEs(0), + mMiscFlags(0) { mPrimitiveCode = 0; @@ -167,20 +171,12 @@ LLPrimitive::LLPrimitive() mAngularVelocity.setVec(0.f,0.f,0.f); mScale.setVec(1.f,1.f,1.f); - - mNumTEs = 0; - mTextureList = NULL; } //=============================================================== LLPrimitive::~LLPrimitive() { - if (mTextureList) - { - delete [] mTextureList; - mTextureList = NULL; - } - + clearTextureList(); // Cleanup handled by volume manager if (mVolumep) { @@ -189,6 +185,10 @@ LLPrimitive::~LLPrimitive() mVolumep = NULL; } +void LLPrimitive::clearTextureList() +{ +} + //=============================================================== // static LLPrimitive *LLPrimitive::createPrimitive(LLPCode p_code) @@ -212,15 +212,7 @@ LLPrimitive *LLPrimitive::createPrimitive(LLPCode p_code) void LLPrimitive::init_primitive(LLPCode p_code) { LLMemType m1(LLMemType::MTYPE_PRIMITIVE); - if (mNumTEs) - { - if (mTextureList) - { - delete [] mTextureList; - } - mTextureList = new LLTextureEntry[mNumTEs]; - } - + clearTextureList(); mPrimitiveCode = p_code; } @@ -230,342 +222,147 @@ void LLPrimitive::setPCode(const U8 p_code) } //=============================================================== -const LLTextureEntry * LLPrimitive::getTE(const U8 te_num) const +LLTextureEntry* LLPrimitive::getTE(const U8 index) const { - // if we're asking for a non-existent face, return null - if (mNumTEs && (te_num< mNumTEs)) - { - return(&mTextureList[te_num]); - } - else - { - return(NULL); - } + return mTextureList.getTexture(index); } //=============================================================== void LLPrimitive::setNumTEs(const U8 num_tes) { - if (num_tes == mNumTEs) - { - return; - } - - // Right now, we don't try and preserve entries when the number of faces - // changes. - - LLMemType m1(LLMemType::MTYPE_PRIMITIVE); - if (num_tes) - { - LLTextureEntry *new_tes; - new_tes = new LLTextureEntry[num_tes]; - U32 i; - for (i = 0; i < num_tes; i++) - { - if (i < mNumTEs) - { - new_tes[i] = mTextureList[i]; - } - else if (mNumTEs) - { - new_tes[i] = mTextureList[mNumTEs - 1]; - } - else - { - new_tes[i] = LLTextureEntry(); - } - } - delete[] mTextureList; - mTextureList = new_tes; - } - else - { - delete[] mTextureList; - mTextureList = NULL; - } - - - mNumTEs = num_tes; + mTextureList.setSize(num_tes); } //=============================================================== void LLPrimitive::setAllTETextures(const LLUUID &tex_id) { - U8 i; - - for (i = 0; i < mNumTEs; i++) - { - mTextureList[i].setID(tex_id); - } + mTextureList.setAllIDs(tex_id); } //=============================================================== -void LLPrimitive::setTE(const U8 index, const LLTextureEntry &te) +void LLPrimitive::setTE(const U8 index, const LLTextureEntry& te) { - mTextureList[index] = te; + mTextureList.copyTexture(index, te); } -S32 LLPrimitive::setTETexture(const U8 te, const LLUUID &tex_id) +S32 LLPrimitive::setTETexture(const U8 index, const LLUUID &id) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setID(tex_id); + return mTextureList.setID(index, id); } -S32 LLPrimitive::setTEColor(const U8 te, const LLColor4 &color) +S32 LLPrimitive::setTEColor(const U8 index, const LLColor4 &color) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - return mTextureList[te].setColor(color); + return mTextureList.setColor(index, color); } -S32 LLPrimitive::setTEColor(const U8 te, const LLColor3 &color) +S32 LLPrimitive::setTEColor(const U8 index, const LLColor3 &color) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setColor(color); + return mTextureList.setColor(index, color); } -S32 LLPrimitive::setTEAlpha(const U8 te, const F32 alpha) +S32 LLPrimitive::setTEAlpha(const U8 index, const F32 alpha) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setAlpha(alpha); + return mTextureList.setAlpha(index, alpha); } //=============================================================== -S32 LLPrimitive::setTEScale(const U8 te, const F32 s, const F32 t) +S32 LLPrimitive::setTEScale(const U8 index, const F32 s, const F32 t) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "Setting nonexistent face" << llendl; - return 0; - } - - return mTextureList[te].setScale(s,t); + return mTextureList.setScale(index, s, t); } // BUG: slow - done this way because texture entries have some // voodoo related to texture coords -S32 LLPrimitive::setTEScaleS(const U8 te, const F32 s) +S32 LLPrimitive::setTEScaleS(const U8 index, const F32 s) { - if (te >= mNumTEs) - { - llwarns << "Setting nonexistent face" << llendl; - return 0; - } - - F32 ignore, t; - mTextureList[te].getScale(&ignore, &t); - return mTextureList[te].setScale(s,t); + return mTextureList.setScaleS(index, s); } // BUG: slow - done this way because texture entries have some // voodoo related to texture coords -S32 LLPrimitive::setTEScaleT(const U8 te, const F32 t) +S32 LLPrimitive::setTEScaleT(const U8 index, const F32 t) { - if (te >= mNumTEs) - { - llwarns << "Setting nonexistent face" << llendl; - return 0; - } - - F32 s, ignore; - mTextureList[te].getScale(&s, &ignore); - return mTextureList[te].setScale(s,t); + return mTextureList.setScaleT(index, t); } //=============================================================== -S32 LLPrimitive::setTEOffset(const U8 te, const F32 s, const F32 t) +S32 LLPrimitive::setTEOffset(const U8 index, const F32 s, const F32 t) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "Setting nonexistent face" << llendl; - return 0; - } - - return mTextureList[te].setOffset(s,t); + return mTextureList.setOffset(index, s, t); } // BUG: slow - done this way because texture entries have some // voodoo related to texture coords -S32 LLPrimitive::setTEOffsetS(const U8 te, const F32 s) +S32 LLPrimitive::setTEOffsetS(const U8 index, const F32 s) { - if (te >= mNumTEs) - { - llwarns << "Setting nonexistent face" << llendl; - return 0; - } - - F32 ignore, t; - mTextureList[te].getOffset(&ignore, &t); - return mTextureList[te].setOffset(s,t); + return mTextureList.setOffsetS(index, s); } // BUG: slow - done this way because texture entries have some // voodoo related to texture coords -S32 LLPrimitive::setTEOffsetT(const U8 te, const F32 t) +S32 LLPrimitive::setTEOffsetT(const U8 index, const F32 t) { - if (te >= mNumTEs) - { - llwarns << "Setting nonexistent face" << llendl; - return 0; - } - - F32 s, ignore; - mTextureList[te].getOffset(&s, &ignore); - return mTextureList[te].setOffset(s,t); + return mTextureList.setOffsetT(index, t); } //=============================================================== -S32 LLPrimitive::setTERotation(const U8 te, const F32 r) +S32 LLPrimitive::setTERotation(const U8 index, const F32 r) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "Setting nonexistent face" << llendl; - return 0; - } - - return mTextureList[te].setRotation(r); + return mTextureList.setRotation(index, r); } //=============================================================== -S32 LLPrimitive::setTEBumpShinyFullbright(const U8 te, const U8 bump) +S32 LLPrimitive::setTEBumpShinyFullbright(const U8 index, const U8 bump) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setBumpShinyFullbright( bump ); + return mTextureList.setBumpShinyFullbright(index, bump); } -S32 LLPrimitive::setTEMediaTexGen(const U8 te, const U8 media) +S32 LLPrimitive::setTEMediaTexGen(const U8 index, const U8 media) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setMediaTexGen( media ); + return mTextureList.setMediaTexGen(index, media); } -S32 LLPrimitive::setTEBumpmap(const U8 te, const U8 bump) +S32 LLPrimitive::setTEBumpmap(const U8 index, const U8 bump) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setBumpmap( bump ); + return mTextureList.setBumpMap(index, bump); } -S32 LLPrimitive::setTEBumpShiny(const U8 te, const U8 bump_shiny) +S32 LLPrimitive::setTEBumpShiny(const U8 index, const U8 bump_shiny) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setBumpShiny( bump_shiny ); + return mTextureList.setBumpShiny(index, bump_shiny); } -S32 LLPrimitive::setTETexGen(const U8 te, const U8 texgen) +S32 LLPrimitive::setTETexGen(const U8 index, const U8 texgen) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setTexGen( texgen ); + return mTextureList.setTexGen(index, texgen); } -S32 LLPrimitive::setTEShiny(const U8 te, const U8 shiny) +S32 LLPrimitive::setTEShiny(const U8 index, const U8 shiny) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setShiny( shiny ); + return mTextureList.setShiny(index, shiny); } -S32 LLPrimitive::setTEFullbright(const U8 te, const U8 fullbright) +S32 LLPrimitive::setTEFullbright(const U8 index, const U8 fullbright) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setFullbright( fullbright ); + return mTextureList.setFullbright(index, fullbright); } -S32 LLPrimitive::setTEMediaFlags(const U8 te, const U8 media_flags) +S32 LLPrimitive::setTEMediaFlags(const U8 index, const U8 media_flags) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setMediaFlags( media_flags ); + return mTextureList.setMediaFlags(index, media_flags); } -S32 LLPrimitive::setTEGlow(const U8 te, const F32 glow) +S32 LLPrimitive::setTEGlow(const U8 index, const F32 glow) { - // if we're asking for a non-existent face, return null - if (te >= mNumTEs) - { - llwarns << "setting non-existent te " << te << llendl; - return 0; - } - - return mTextureList[te].setGlow( glow ); + return mTextureList.setGlow(index, glow); } @@ -877,25 +674,18 @@ std::string LLPrimitive::pCodeToString(const LLPCode pcode) void LLPrimitive::copyTEs(const LLPrimitive *primitivep) { U32 i; - if (primitivep->getNumTEs() != getNumTEs()) + if (primitivep->getExpectedNumTEs() != getExpectedNumTEs()) + { + llwarns << "Primitives don't have same expected number of TE's" << llendl; + } + U32 num_tes = llmin(primitivep->getExpectedNumTEs(), getExpectedNumTEs()); + if (mTextureList.size() < getExpectedNumTEs()) { - llwarns << "Primitives don't have same number of TE's" << llendl; + mTextureList.setSize(getExpectedNumTEs()); } - U32 num_tes = llmin(primitivep->getNumTEs(), getNumTEs()); for (i = 0; i < num_tes; i++) { - const LLTextureEntry *tep = primitivep->getTE(i); - F32 s, t; - setTETexture(i, tep->getID()); - setTEColor(i, tep->getColor()); - tep->getScale(&s, &t); - setTEScale(i, s, t); - tep->getOffset(&s, &t); - setTEOffset(i, s, t); - setTERotation(i, tep->getRotation()); - setTEBumpShinyFullbright(i, tep->getBumpShinyFullbright()); - setTEMediaTexGen(i, tep->getMediaTexGen()); - setTEGlow(i, tep->getGlow()); + mTextureList.copyTexture(i, *(primitivep->getTE(i))); } } @@ -957,73 +747,208 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai U32 old_face_mask = mVolumep->mFaceMask; + + S32 face_bit = 0; + S32 cur_mask = 0; + + // Grab copies of the old faces from the original shape, ordered by type. + // We will use these to figure out what old texture info gets mapped to new + // faces in the new shape. + std::vector<LLProfile::Face> old_faces; + for (S32 face = 0; face < mVolumep->getNumFaces(); face++) + { + old_faces.push_back(mVolumep->getProfile().mFaces[face]); + } + + // Copy the old texture info off to the side, but not in the order in which + // they live in the mTextureList, rather in order of ther "face id" which + // is the corresponding value of LLVolueParams::LLProfile::mFaces::mIndex. + // + // Hence, some elements of old_tes::mEntryList will be invalid. It is + // initialized to a size of 9 (max number of possible faces on a volume?) + // and only the ones with valid types are filled in. + LLPrimTextureList old_tes; + old_tes.setSize(9); + for (face_bit = 0; face_bit < 9; face_bit++) + { + cur_mask = 0x1 << face_bit; + if (old_face_mask & cur_mask) + { + S32 te_index = face_index_from_id(cur_mask, old_faces); + old_tes.copyTexture(face_bit, *(getTE(te_index))); + //llinfos << face_bit << ":" << te_index << ":" << old_tes[face_bit].getID() << llendl; + } + } + + // build the new object sVolumeManager->unrefVolume(mVolumep); mVolumep = volumep; - U32 new_face_mask = mVolumep->mFaceMask; - if (old_face_mask != new_face_mask) - { - setNumTEs(mVolumep->getNumFaces()); - } - - return TRUE; -} + U32 new_face_mask = mVolumep->mFaceMask; + S32 i; -BOOL LLPrimitive::setMaterial(U8 material) -{ - if (material != mMaterial) + if (old_face_mask == new_face_mask) { - mMaterial = material; + setNumTEs(mVolumep->getNumFaces()); return TRUE; } - else - { - return FALSE; - } -} -void LLPrimitive::setTEArrays(const U8 size, - const LLUUID* image_ids, - const F32* scale_s, - const F32* scale_t) -{ - S32 cur_size = size; - if (cur_size > getNumTEs()) + // initialize face_mapping + S32 face_mapping[9]; + for (face_bit = 0; face_bit < 9; face_bit++) { - llwarns << "Trying to set more TEs than exist!" << llendl; - cur_size = getNumTEs(); + face_mapping[face_bit] = face_bit; } - S32 i; - // Copy over image information - for (i = 0; i < cur_size; i++) + // The new shape may have more faces than the original, but we can't just + // add them to the end -- the ordering matters and it may be that we must + // insert the new faces in the middle of the list. When we add a face it + // will pick up the texture/color info of one of the old faces an so we + // now figure out which old face info gets mapped to each new face, and + // store in the face_mapping lookup table. + for (face_bit = 0; face_bit < 9; face_bit++) { - // This is very BAD!!!!!! - if (image_ids != NULL) + cur_mask = 0x1 << face_bit; + if (!(new_face_mask & cur_mask)) { - setTETexture(i,image_ids[i]); + // Face doesn't exist in new map. + face_mapping[face_bit] = -1; + continue; } - if (scale_s && scale_t) + else if (old_face_mask & cur_mask) { - setTEScale(i, scale_s[i], scale_t[i]); + // Face exists in new and old map. + face_mapping[face_bit] = face_bit; + continue; } - } - if (i < getNumTEs()) - { - cur_size--; - for (i=i; i < getNumTEs(); i++) // the i=i removes a gcc warning + // OK, how we've got a mismatch, where we have to fill a new face with one from + // the old face. + if (cur_mask & (LL_FACE_PATH_BEGIN | LL_FACE_PATH_END | LL_FACE_INNER_SIDE)) { - if (image_ids != NULL) + // It's a top/bottom/hollow interior face. + if (old_face_mask & LL_FACE_PATH_END) { - setTETexture(i, image_ids[cur_size]); + face_mapping[face_bit] = 1; + continue; } - if (scale_s && scale_t) + else { - setTEScale(i, scale_s[cur_size], scale_t[cur_size]); + S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0; + for (i = 0; i < 4; i++) + { + if (old_face_mask & cur_outer_mask) + { + face_mapping[face_bit] = 5 + i; + break; + } + cur_outer_mask <<= 1; + } + if (i == 4) + { + llwarns << "No path end or outer face in volume!" << llendl; + } + continue; } } + + if (cur_mask & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END)) + { + // A cut slice. Use the hollow interior if we have it. + if (old_face_mask & LL_FACE_INNER_SIDE) + { + face_mapping[face_bit] = 2; + continue; + } + + // No interior, use the bottom face. + // Could figure out which of the outer faces was nearest, but that would be harder. + if (old_face_mask & LL_FACE_PATH_END) + { + face_mapping[face_bit] = 1; + continue; + } + else + { + S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0; + for (i = 0; i < 4; i++) + { + if (old_face_mask & cur_outer_mask) + { + face_mapping[face_bit] = 5 + i; + break; + } + cur_outer_mask <<= 1; + } + if (i == 4) + { + llwarns << "No path end or outer face in volume!" << llendl; + } + continue; + } + } + + // OK, the face that's missing is an outer face... + // Pull from the nearest adjacent outer face (there's always guaranteed to be one... + S32 cur_outer = face_bit - 5; + S32 min_dist = 5; + S32 min_outer_bit = -1; + S32 i; + for (i = 0; i < 4; i++) + { + if (old_face_mask & (LL_FACE_OUTER_SIDE_0 << i)) + { + S32 dist = abs(i - cur_outer); + if (dist < min_dist) + { + min_dist = dist; + min_outer_bit = i + 5; + } + } + } + if (-1 == min_outer_bit) + { + llinfos << (LLVolume *)mVolumep << llendl; + llwarns << "Bad! No outer faces, impossible!" << llendl; + } + face_mapping[face_bit] = min_outer_bit; + } + + + setNumTEs(mVolumep->getNumFaces()); + for (face_bit = 0; face_bit < 9; face_bit++) + { + // For each possible face type on the new shape we check to see if that + // face exists and if it does we create a texture entry that is a copy + // of one of the originals. Since the originals might not have a + // matching face, we use the face_mapping lookup table to figure out + // which face information to copy. + cur_mask = 0x1 << face_bit; + if (new_face_mask & cur_mask) + { + if (-1 == face_mapping[face_bit]) + { + llwarns << "No mapping from old face to new face!" << llendl; + } + + S32 te_num = face_index_from_id(cur_mask, mVolumep->getProfile().mFaces); + setTE(te_num, *(old_tes.getTexture(face_mapping[face_bit]))); + } + } + return TRUE; +} + +BOOL LLPrimitive::setMaterial(U8 material) +{ + if (material != mMaterial) + { + mMaterial = material; + return TRUE; + } + else + { + return FALSE; } } @@ -1178,6 +1103,7 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys, int shield) const else memcpy(&image_ids[face_index*16],LLUUID("4934f1bf-3b1f-cf4f-dbdf-a72550d05bc6").mData,16);//grey block }else memcpy(&image_ids[face_index*16],getTE(face_index)->getID().mData,16); /* Flawfinder: ignore */ + // Cast LLColor4 to LLColor4U coloru.setVec( getTE(face_index)->getColor() ); @@ -1402,6 +1328,7 @@ S32 LLPrimitive::unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, con color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f; retval |= setTEColor(i, color); + } return retval; @@ -1501,11 +1428,24 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) return retval; } -void LLPrimitive::setTextureList(LLTextureEntry *listp) +U8 LLPrimitive::getExpectedNumTEs() const +{ + U8 expected_face_count = 0; + if (mVolumep) + { + expected_face_count = mVolumep->getNumFaces(); + } + return expected_face_count; +} + +void LLPrimitive::copyTextureList(const LLPrimTextureList& other_list) +{ + mTextureList.copy(other_list); +} + +void LLPrimitive::takeTextureList(LLPrimTextureList& other_list) { - LLTextureEntry* old_texture_list = mTextureList; - mTextureList = listp; - delete[] old_texture_list; + mTextureList.take(other_list); } //============================================================================ @@ -1569,6 +1509,8 @@ BOOL LLNetworkData::isValid(U16 param_type, U32 size) return (size == 16); case PARAMS_SCULPT: return (size == 17); + case PARAMS_LIGHT_IMAGE: + return (size == 28); } return FALSE; @@ -1901,3 +1843,78 @@ bool LLSculptParams::fromLLSD(LLSD& sd) return false; } +//============================================================================ + +LLLightImageParams::LLLightImageParams() +{ + mType = PARAMS_LIGHT_IMAGE; + mParams.setVec(F_PI*0.5f, 0.f, 0.f); +} + +BOOL LLLightImageParams::pack(LLDataPacker &dp) const +{ + dp.packUUID(mLightTexture, "texture"); + dp.packVector3(mParams, "params"); + + return TRUE; +} + +BOOL LLLightImageParams::unpack(LLDataPacker &dp) +{ + dp.unpackUUID(mLightTexture, "texture"); + dp.unpackVector3(mParams, "params"); + + return TRUE; +} + +bool LLLightImageParams::operator==(const LLNetworkData& data) const +{ + if (data.mType != PARAMS_LIGHT_IMAGE) + { + return false; + } + + const LLLightImageParams *param = (const LLLightImageParams*)&data; + if ( (param->mLightTexture != mLightTexture) ) + { + return false; + } + + if ( (param->mParams != mParams ) ) + { + return false; + } + + return true; +} + +void LLLightImageParams::copy(const LLNetworkData& data) +{ + const LLLightImageParams *param = (LLLightImageParams*)&data; + mLightTexture = param->mLightTexture; + mParams = param->mParams; +} + + + +LLSD LLLightImageParams::asLLSD() const +{ + LLSD sd; + + sd["texture"] = mLightTexture; + sd["params"] = mParams.getValue(); + + return sd; +} + +bool LLLightImageParams::fromLLSD(LLSD& sd) +{ + if (sd.has("texture")) + { + setLightTexture( sd["texture"] ); + setParams( LLVector3( sd["params"] ) ); + return true; + } + + return false; +} diff --git a/linden/indra/llprimitive/llprimitive.h b/linden/indra/llprimitive/llprimitive.h old mode 100644 new mode 100755 index efabb8251..e146fbe93 --- a/linden/indra/llprimitive/llprimitive.h +++ b/linden/indra/llprimitive/llprimitive.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -37,9 +37,11 @@ #include "v3math.h" #include "xform.h" #include "message.h" -#include "llmemory.h" +#include "llmemory.h" // not in SG2.0 +//#include "llpointer.h"// instead in SG2.0 #include "llvolume.h" #include "lltextureentry.h" +#include "llprimtexturelist.h" // Moved to stdtypes.h --JC // typedef U8 LLPCode; @@ -105,7 +107,8 @@ class LLNetworkData { PARAMS_FLEXIBLE = 0x10, PARAMS_LIGHT = 0x20, - PARAMS_SCULPT = 0x30 + PARAMS_SCULPT = 0x30, + PARAMS_LIGHT_IMAGE = 0x40, }; public: @@ -260,11 +263,33 @@ class LLSculptParams : public LLNetworkData bool fromLLSD(LLSD& sd); void setSculptTexture(const LLUUID& id) { mSculptTexture = id; } - LLUUID getSculptTexture() { return mSculptTexture; } + LLUUID getSculptTexture() const { return mSculptTexture; } void setSculptType(U8 type) { mSculptType = type; } - U8 getSculptType() { return mSculptType; } + U8 getSculptType() const { return mSculptType; } }; +class LLLightImageParams : public LLNetworkData +{ +protected: + LLUUID mLightTexture; + LLVector3 mParams; + +public: + LLLightImageParams(); + /*virtual*/ BOOL pack(LLDataPacker &dp) const; + /*virtual*/ BOOL unpack(LLDataPacker &dp); + /*virtual*/ bool operator==(const LLNetworkData& data) const; + /*virtual*/ void copy(const LLNetworkData& data); + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + void setLightTexture(const LLUUID& id) { mLightTexture = id; } + LLUUID getLightTexture() const { return mLightTexture; } + void setParams(const LLVector3& params) { mParams = params; } + LLVector3 getParams() const { return mParams; } + +}; class LLPrimitive : public LLXform @@ -294,6 +319,8 @@ class LLPrimitive : public LLXform LLPrimitive(); virtual ~LLPrimitive(); + void clearTextureList(); + static LLPrimitive *createPrimitive(LLPCode p_code); void init_primitive(LLPCode p_code); @@ -304,11 +331,11 @@ class LLPrimitive : public LLXform // Modify texture entry properties inline BOOL validTE(const U8 te_num) const; - const LLTextureEntry *getTE(const U8 te_num) const; + LLTextureEntry* getTE(const U8 te_num) const; virtual void setNumTEs(const U8 num_tes); virtual void setAllTETextures(const LLUUID &tex_id); - virtual void setTE(const U8 index, const LLTextureEntry &te); + virtual void setTE(const U8 index, const LLTextureEntry& te); virtual S32 setTEColor(const U8 te, const LLColor4 &color); virtual S32 setTEColor(const U8 te, const LLColor3 &color); virtual S32 setTEAlpha(const U8 te, const F32 alpha); @@ -331,10 +358,6 @@ class LLPrimitive : public LLXform virtual S32 setTEGlow(const U8 te, const F32 glow); virtual BOOL setMaterial(const U8 material); // returns TRUE if material changed - void setTEArrays(const U8 size, - const LLUUID* image_ids, - const F32* scale_s, - const F32* scale_t); void copyTEs(const LLPrimitive *primitive); S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const; S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type); @@ -382,14 +405,21 @@ class LLPrimitive : public LLXform const LLVector3& getAngularVelocity() const { return mAngularVelocity; } const LLVector3& getVelocity() const { return mVelocity; } const LLVector3& getAcceleration() const { return mAcceleration; } - U8 getNumTEs() const { return mNumTEs; } + U8 getNumTEs() const { return mTextureList.size(); } + U8 getExpectedNumTEs() const; U8 getMaterial() const { return mMaterial; } void setVolumeType(const U8 code); U8 getVolumeType(); - void setTextureList(LLTextureEntry *listp); + // clears existing textures + // copies the contents of other_list into mEntryList + void copyTextureList(const LLPrimTextureList& other_list); + + // clears existing textures + // takes the contents of other_list and clears other_list + void takeTextureList(LLPrimTextureList& other_list); inline BOOL isAvatar() const; inline BOOL isSittingAvatar() const; @@ -414,7 +444,7 @@ class LLPrimitive : public LLXform LLVector3 mAcceleration; // are we under constant acceleration? LLVector3 mAngularVelocity; // angular velocity LLPointer<LLVolume> mVolumep; - LLTextureEntry *mTextureList; // list of texture GUIDs, scales, offsets + LLPrimTextureList mTextureList; // list of texture GUIDs, scales, offsets U8 mMaterial; // Material code U8 mNumTEs; // # of faces on the primitve U32 mMiscFlags; // home for misc bools diff --git a/linden/indra/llprimitive/llprimlinkinfo.h b/linden/indra/llprimitive/llprimlinkinfo.h old mode 100644 new mode 100755 index 946fa75bf..dfe33c1d0 --- a/linden/indra/llprimitive/llprimlinkinfo.h +++ b/linden/indra/llprimitive/llprimlinkinfo.h @@ -5,7 +5,7 @@ * * $LicenseInfo:firstyear=2007&license=viewergpl$ * - * Copyright (c) 2007-2009, Linden Research, Inc. + * Copyright (c) 2007-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab diff --git a/linden/indra/llprimitive/llprimtexturelist.cpp b/linden/indra/llprimitive/llprimtexturelist.cpp new file mode 100755 index 000000000..691eb760e --- /dev/null +++ b/linden/indra/llprimitive/llprimtexturelist.cpp @@ -0,0 +1,424 @@ +/** + * @file lltexturelist.cpp + * @brief LLPrimTextureList (virtual) base class + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llprimtexturelist.h" +#include "lltextureentry.h" +#include "llmemtype.h" + +// static +//int (TMyClass::*pt2Member)(float, char, char) = NULL; // C++ +LLTextureEntry* (*LLPrimTextureList::sNewTextureEntryCallback)() = &(LLTextureEntry::newTextureEntry); + +// static +void LLPrimTextureList::setNewTextureEntryCallback( LLTextureEntry* (*callback)() ) +{ + if (callback) + { + LLPrimTextureList::sNewTextureEntryCallback = callback; + } + else + { + LLPrimTextureList::sNewTextureEntryCallback = &(LLTextureEntry::newTextureEntry); + } +} + +// static +// call this to get a new texture entry +LLTextureEntry* LLPrimTextureList::newTextureEntry() +{ + return (*sNewTextureEntryCallback)(); +} + +LLPrimTextureList::LLPrimTextureList() +{ +} + +// virtual +LLPrimTextureList::~LLPrimTextureList() +{ + clear(); +} + +void LLPrimTextureList::clear() +{ + texture_list_t::iterator itr = mEntryList.begin(); + while (itr != mEntryList.end()) + { + delete (*itr); + (*itr) = NULL; + ++itr; + } + mEntryList.clear(); +} + + +// clears current entries +// copies contents of other_list +// this is somewhat expensive, so it must be called explicitly +void LLPrimTextureList::copy(const LLPrimTextureList& other_list) +{ + // compare the sizes + S32 this_size = mEntryList.size(); + S32 other_size = other_list.mEntryList.size(); + + if (this_size > other_size) + { + // remove the extra entries + for (S32 index = this_size; index > other_size; --index) + { + delete mEntryList[index-1]; + } + mEntryList.resize(other_size); + this_size = other_size; + } + + S32 index = 0; + // copy for the entries that already exist + for ( ; index < this_size; ++index) + { + delete mEntryList[index]; + mEntryList[index] = other_list.getTexture(index)->newCopy(); + } + + // add new entires if needed + for ( ; index < other_size; ++index) + { + mEntryList.push_back( other_list.getTexture(index)->newCopy() ); + } +} + +// clears current copies +// takes contents of other_list +// clears other_list +void LLPrimTextureList::take(LLPrimTextureList& other_list) +{ + clear(); + mEntryList = other_list.mEntryList; + other_list.mEntryList.clear(); +} + +// virtual +// copies LLTextureEntry 'te' +// returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE +S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te) +{ + if (S32(index) >= mEntryList.size()) + { + S32 current_size = mEntryList.size(); + llwarns << "ignore copy of index = " << S32(index) << " into texture entry list of size = " << current_size << llendl; + return TEM_CHANGE_NONE; + } + + // we're changing an existing entry + llassert(mEntryList[index]); + delete (mEntryList[index]); + if (&te) + { + mEntryList[index] = te.newCopy(); + } + else + { + mEntryList[index] = LLPrimTextureList::newTextureEntry(); + } + return TEM_CHANGE_TEXTURE; +} + +// virtual +// takes ownership of LLTextureEntry* 'te' +// returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE +// IMPORTANT! -- if you use this function you must check the return value +S32 LLPrimTextureList::takeTexture(const U8 index, LLTextureEntry* te) +{ + if (S32(index) >= mEntryList.size()) + { + return TEM_CHANGE_NONE; + } + + // we're changing an existing entry + llassert(mEntryList[index]); + delete (mEntryList[index]); + mEntryList[index] = te; + return TEM_CHANGE_TEXTURE; +} + +// returns pointer to texture at 'index' slot +LLTextureEntry* LLPrimTextureList::getTexture(const U8 index) const +{ + if (index < mEntryList.size()) + { + return mEntryList[index]; + } + return NULL; +} + +//virtual +//S32 setTE(const U8 index, const LLTextureEntry& te) = 0; + +S32 LLPrimTextureList::setID(const U8 index, const LLUUID& id) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setID(id); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setColor(const U8 index, const LLColor3& color) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setColor(color); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setColor(const U8 index, const LLColor4& color) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setColor(color); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setAlpha(const U8 index, const F32 alpha) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setAlpha(alpha); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setScale(const U8 index, const F32 s, const F32 t) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setScale(s, t); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setScaleS(const U8 index, const F32 s) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setScaleS(s); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setScaleT(const U8 index, const F32 t) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setScaleT(t); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setOffset(const U8 index, const F32 s, const F32 t) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setOffset(s, t); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setOffsetS(const U8 index, const F32 s) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setOffsetS(s); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setOffsetT(const U8 index, const F32 t) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setOffsetT(t); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setRotation(const U8 index, const F32 r) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setRotation(r); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setBumpShinyFullbright(const U8 index, const U8 bump) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setBumpShinyFullbright(bump); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setMediaTexGen(const U8 index, const U8 media) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setMediaTexGen(media); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setBumpMap(const U8 index, const U8 bump) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setBumpmap(bump); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setBumpShiny(const U8 index, const U8 bump_shiny) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setBumpShiny(bump_shiny); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setTexGen(const U8 index, const U8 texgen) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setTexGen(texgen); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setShiny(const U8 index, const U8 shiny) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setShiny(shiny); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setFullbright(const U8 index, const U8 fullbright) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setFullbright(fullbright); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setMediaFlags(const U8 index, const U8 media_flags) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setMediaFlags(media_flags); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setGlow(const U8 index, const F32 glow) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setGlow(glow); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::size() const +{ + return mEntryList.size(); +} + +// sets the size of the mEntryList container +void LLPrimTextureList::setSize(S32 new_size) +{ + LLMemType m1(LLMemType::MTYPE_PRIMITIVE); + if (new_size < 0) + { + new_size = 0; + } + + S32 current_size = mEntryList.size(); + + if (new_size > current_size) + { + mEntryList.resize(new_size); + for (S32 index = current_size; index < new_size; ++index) + { + if (current_size > 0 + && mEntryList[current_size - 1]) + { + // copy the last valid entry for the new one + mEntryList[index] = mEntryList[current_size - 1]->newCopy(); + } + else + { + // no valid enries to copy, so we new one up + LLTextureEntry* new_entry = LLPrimTextureList::newTextureEntry(); + mEntryList[index] = new_entry; + } + } + } + else if (new_size < current_size) + { + for (S32 index = current_size-1; index >= new_size; --index) + { + delete mEntryList[index]; + } + mEntryList.resize(new_size); + } +} + + +void LLPrimTextureList::setAllIDs(const LLUUID& id) +{ + texture_list_t::iterator itr = mEntryList.begin(); + while (itr != mEntryList.end()) + { + (*itr)->setID(id); + ++itr; + } +} + + diff --git a/linden/indra/llprimitive/llprimtexturelist.h b/linden/indra/llprimitive/llprimtexturelist.h new file mode 100755 index 000000000..c62f7b935 --- /dev/null +++ b/linden/indra/llprimitive/llprimtexturelist.h @@ -0,0 +1,127 @@ +/** + * @file llprimtexturelist.h + * @brief LLPrimTextureList (virtual) base class + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPRIMTEXTURELIST_H +#define LL_LLPRIMTEXTURELIST_H + +#include <vector> +#include "lluuid.h" +#include "v3color.h" +#include "v4color.h" + + +class LLTextureEntry; + +// this is a list of LLTextureEntry*'s because in practice the list's elements +// are of some derived class: LLFooTextureEntry +typedef std::vector<LLTextureEntry*> texture_list_t; + +class LLPrimTextureList +{ +public: + // the LLPrimTextureList needs to know what type of LLTextureEntry + // to generate when it needs a new one, so we may need to set a + // callback for generating it, (or else use the base class default: + // static LLPrimTextureEntry::newTextureEntry() ) + //typedef LLTextureEntry* (__stdcall *NewTextureEntryFunction)(); + //static NewTextureEntryFunction sNewTextureEntryCallback; + static LLTextureEntry* newTextureEntry(); + static void setNewTextureEntryCallback( LLTextureEntry* (*callback)() ); + static LLTextureEntry* (*sNewTextureEntryCallback)(); + + LLPrimTextureList(); + virtual ~LLPrimTextureList(); + + void clear(); + + // clears current entries + // copies contents of other_list + // this is somewhat expensive, so it must be called explicitly + void copy(const LLPrimTextureList& other_list); + + // clears current copies + // takes contents of other_list + // clears other_list + void take(LLPrimTextureList& other_list); + + // copies LLTextureEntry 'te' + // returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE + S32 copyTexture(const U8 index, const LLTextureEntry& te); + + // takes ownership of LLTextureEntry* 'te' + // returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE + // IMPORTANT! -- if you use this function you must check the return value + S32 takeTexture(const U8 index, LLTextureEntry* te); + +// // copies contents of 'entry' and stores it in 'index' slot +// void copyTexture(const U8 index, const LLTextureEntry* entry); + + // returns pointer to texture at 'index' slot + LLTextureEntry* getTexture(const U8 index) const; + + S32 setID(const U8 index, const LLUUID& id); + S32 setColor(const U8 index, const LLColor3& color); + S32 setColor(const U8 index, const LLColor4& color); + S32 setAlpha(const U8 index, const F32 alpha); + S32 setScale(const U8 index, const F32 s, const F32 t); + S32 setScaleS(const U8 index, const F32 s); + S32 setScaleT(const U8 index, const F32 t); + S32 setOffset(const U8 index, const F32 s, const F32 t); + S32 setOffsetS(const U8 index, const F32 s); + S32 setOffsetT(const U8 index, const F32 t); + S32 setRotation(const U8 index, const F32 r); + S32 setBumpShinyFullbright(const U8 index, const U8 bump); + S32 setMediaTexGen(const U8 index, const U8 media); + S32 setBumpMap(const U8 index, const U8 bump); + S32 setBumpShiny(const U8 index, const U8 bump_shiny); + S32 setTexGen(const U8 index, const U8 texgen); + S32 setShiny(const U8 index, const U8 shiny); + S32 setFullbright(const U8 index, const U8 t); + S32 setMediaFlags(const U8 index, const U8 media_flags); + S32 setGlow(const U8 index, const F32 glow); + + S32 size() const; + +// void forceResize(S32 new_size); + void setSize(S32 new_size); + + void setAllIDs(const LLUUID& id); +protected: + texture_list_t mEntryList; +private: + LLPrimTextureList(const LLPrimTextureList& other_list) + { + // private so that it can't be used + } +}; + +#endif diff --git a/linden/indra/llprimitive/lltextureentry.cpp b/linden/indra/llprimitive/lltextureentry.cpp old mode 100644 new mode 100755 index 14b45443d..11afdc02a --- a/linden/indra/llprimitive/lltextureentry.cpp +++ b/linden/indra/llprimitive/lltextureentry.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -32,25 +32,52 @@ #include "linden_common.h" +#include "lluuid.h" +#include "llmediaentry.h" #include "lltextureentry.h" -#include "llsdutil.h" +#include "llsdutil.h"//_math.h" +#include "v4color.h" const U8 DEFAULT_BUMP_CODE = 0; // no bump or shininess const LLTextureEntry LLTextureEntry::null; +// Some LLSD keys. Do not change these! +#define OBJECT_ID_KEY_STR "object_id" +#define TEXTURE_INDEX_KEY_STR "texture_index" +#define OBJECT_MEDIA_VERSION_KEY_STR "object_media_version" +#define OBJECT_MEDIA_DATA_KEY_STR "object_media_data" +#define TEXTURE_MEDIA_DATA_KEY_STR "media_data" + +/*static*/ const char* LLTextureEntry::OBJECT_ID_KEY = OBJECT_ID_KEY_STR; +/*static*/ const char* LLTextureEntry::OBJECT_MEDIA_DATA_KEY = OBJECT_MEDIA_DATA_KEY_STR; +/*static*/ const char* LLTextureEntry::MEDIA_VERSION_KEY = OBJECT_MEDIA_VERSION_KEY_STR; +/*static*/ const char* LLTextureEntry::TEXTURE_INDEX_KEY = TEXTURE_INDEX_KEY_STR; +/*static*/ const char* LLTextureEntry::TEXTURE_MEDIA_DATA_KEY = TEXTURE_MEDIA_DATA_KEY_STR; + +static const std::string MEDIA_VERSION_STRING_PREFIX = "x-mv:"; + +// static +LLTextureEntry* LLTextureEntry::newTextureEntry() +{ + return new LLTextureEntry(); +} + //=============================================================== LLTextureEntry::LLTextureEntry() + : mMediaEntry(NULL) { init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE); } LLTextureEntry::LLTextureEntry(const LLUUID& tex_id) + : mMediaEntry(NULL) { init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE); } LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs) + : mMediaEntry(NULL) { mID = rhs.mID; mScaleS = rhs.mScaleS; @@ -62,6 +89,10 @@ LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs) mBump = rhs.mBump; mMediaFlags = rhs.mMediaFlags; mGlow = rhs.mGlow; + if (rhs.mMediaEntry != NULL) { + // Make a copy + mMediaEntry = new LLMediaEntry(*rhs.mMediaEntry); + } } LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs) @@ -78,6 +109,16 @@ LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs) mBump = rhs.mBump; mMediaFlags = rhs.mMediaFlags; mGlow = rhs.mGlow; + if (mMediaEntry != NULL) { + delete mMediaEntry; + } + if (rhs.mMediaEntry != NULL) { + // Make a copy + mMediaEntry = new LLMediaEntry(*rhs.mMediaEntry); + } + else { + mMediaEntry = NULL; + } } return *this; @@ -97,10 +138,19 @@ void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 of mGlow = 0; setColor(LLColor4(1.f, 1.f, 1.f, 1.f)); + if (mMediaEntry != NULL) { + delete mMediaEntry; + } + mMediaEntry = NULL; } LLTextureEntry::~LLTextureEntry() { + if(mMediaEntry) + { + delete mMediaEntry; + mMediaEntry = NULL; + } } bool LLTextureEntry::operator!=(const LLTextureEntry &rhs) const @@ -136,23 +186,33 @@ bool LLTextureEntry::operator==(const LLTextureEntry &rhs) const LLSD LLTextureEntry::asLLSD() const { LLSD sd; + asLLSD(sd); + return sd; +} - sd["imageid"] = getID(); - sd["colors"] = ll_sd_from_color4(getColor()); +void LLTextureEntry::asLLSD(LLSD& sd) const +{ + sd["imageid"] = mID; + sd["colors"] = ll_sd_from_color4(mColor); sd["scales"] = mScaleS; sd["scalet"] = mScaleT; sd["offsets"] = mOffsetS; sd["offsett"] = mOffsetT; - sd["imagerot"] = getRotation(); + sd["imagerot"] = mRotation; sd["bump"] = getBumpShiny(); sd["fullbright"] = getFullbright(); - sd["media_flags"] = getMediaTexGen(); - sd["glow"] = getGlow(); - - return sd; + sd["media_flags"] = mMediaFlags; + if (hasMedia()) { + LLSD mediaData; + if (NULL != getMediaData()) { + getMediaData()->asLLSD(mediaData); + } + sd[TEXTURE_MEDIA_DATA_KEY] = mediaData; + } + sd["glow"] = mGlow; } -bool LLTextureEntry::fromLLSD(LLSD& sd) +bool LLTextureEntry::fromLLSD(const LLSD& sd) { const char *w, *x; w = "imageid"; @@ -197,6 +257,17 @@ bool LLTextureEntry::fromLLSD(LLSD& sd) { setMediaTexGen( sd[w].asInteger() ); } else goto fail; + // If the "has media" flag doesn't match the fact that + // media data exists, updateMediaData will "fix" it + // by either clearing or setting the flag + w = TEXTURE_MEDIA_DATA_KEY; + if (hasMedia() != sd.has(w)) + { + llwarns << "LLTextureEntry::fromLLSD: media_flags (" << hasMedia() << + ") does not match presence of media_data (" << sd.has(w) << "). Fixing." << llendl; + } + updateMediaData(sd[w]); + w = "glow"; if (sd.has(w)) { @@ -208,6 +279,19 @@ bool LLTextureEntry::fromLLSD(LLSD& sd) return false; } +// virtual +// override this method for each derived class +LLTextureEntry* LLTextureEntry::newBlank() const +{ + return new LLTextureEntry(); +} + +// virtual +LLTextureEntry* LLTextureEntry::newCopy() const +{ + return new LLTextureEntry(*this); +} + S32 LLTextureEntry::setID(const LLUUID &tex_id) { if (mID != tex_id) @@ -215,7 +299,7 @@ S32 LLTextureEntry::setID(const LLUUID &tex_id) mID = tex_id; return TEM_CHANGE_TEXTURE; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setScale(F32 s, F32 t) @@ -233,6 +317,28 @@ S32 LLTextureEntry::setScale(F32 s, F32 t) return retval; } +S32 LLTextureEntry::setScaleS(F32 s) +{ + S32 retval = TEM_CHANGE_NONE; + if (mScaleS != s) + { + mScaleS = s; + retval = TEM_CHANGE_TEXTURE; + } + return retval; +} + +S32 LLTextureEntry::setScaleT(F32 t) +{ + S32 retval = TEM_CHANGE_NONE; + if (mScaleT != t) + { + mScaleT = t; + retval = TEM_CHANGE_TEXTURE; + } + return retval; +} + S32 LLTextureEntry::setColor(const LLColor4 &color) { if (mColor != color) @@ -240,7 +346,7 @@ S32 LLTextureEntry::setColor(const LLColor4 &color) mColor = color; return TEM_CHANGE_COLOR; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setColor(const LLColor3 &color) @@ -251,7 +357,7 @@ S32 LLTextureEntry::setColor(const LLColor3 &color) mColor.setVec(color); return TEM_CHANGE_COLOR; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setAlpha(const F32 alpha) @@ -261,7 +367,7 @@ S32 LLTextureEntry::setAlpha(const F32 alpha) mColor.mV[VW] = alpha; return TEM_CHANGE_COLOR; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setOffset(F32 s, F32 t) @@ -279,6 +385,28 @@ S32 LLTextureEntry::setOffset(F32 s, F32 t) return retval; } +S32 LLTextureEntry::setOffsetS(F32 s) +{ + S32 retval = 0; + if (mOffsetS != s) + { + mOffsetS = s; + retval = TEM_CHANGE_TEXTURE; + } + return retval; +} + +S32 LLTextureEntry::setOffsetT(F32 t) +{ + S32 retval = 0; + if (mOffsetT != t) + { + mOffsetT = t; + retval = TEM_CHANGE_TEXTURE; + } + return retval; +} + S32 LLTextureEntry::setRotation(F32 theta) { if (mRotation != theta) @@ -286,7 +414,7 @@ S32 LLTextureEntry::setRotation(F32 theta) mRotation = theta; return TEM_CHANGE_TEXTURE; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setBumpShinyFullbright(U8 bump) @@ -296,7 +424,7 @@ S32 LLTextureEntry::setBumpShinyFullbright(U8 bump) mBump = bump; return TEM_CHANGE_TEXTURE; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setMediaTexGen(U8 media) @@ -304,9 +432,21 @@ S32 LLTextureEntry::setMediaTexGen(U8 media) if (mMediaFlags != media) { mMediaFlags = media; - return TEM_CHANGE_TEXTURE; + + // Special code for media handling + if( hasMedia() && mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + else if ( ! hasMedia() && mMediaEntry != NULL) + { + delete mMediaEntry; + mMediaEntry = NULL; + } + + return TEM_CHANGE_MEDIA; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setBumpmap(U8 bump) @@ -318,7 +458,7 @@ S32 LLTextureEntry::setBumpmap(U8 bump) mBump |= bump; return TEM_CHANGE_TEXTURE; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setFullbright(U8 fullbright) @@ -330,7 +470,7 @@ S32 LLTextureEntry::setFullbright(U8 fullbright) mBump |= fullbright << TEM_FULLBRIGHT_SHIFT; return TEM_CHANGE_TEXTURE; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setShiny(U8 shiny) @@ -342,7 +482,7 @@ S32 LLTextureEntry::setShiny(U8 shiny) mBump |= shiny << TEM_SHINY_SHIFT; return TEM_CHANGE_TEXTURE; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setBumpShiny(U8 bump_shiny) @@ -354,7 +494,7 @@ S32 LLTextureEntry::setBumpShiny(U8 bump_shiny) mBump |= bump_shiny; return TEM_CHANGE_TEXTURE; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setMediaFlags(U8 media_flags) @@ -364,9 +504,21 @@ S32 LLTextureEntry::setMediaFlags(U8 media_flags) { mMediaFlags &= ~TEM_MEDIA_MASK; mMediaFlags |= media_flags; - return TEM_CHANGE_TEXTURE; + + // Special code for media handling + if( hasMedia() && mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + else if ( ! hasMedia() && mMediaEntry != NULL) + { + delete mMediaEntry; + mMediaEntry = NULL; + } + + return TEM_CHANGE_MEDIA; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setTexGen(U8 tex_gen) @@ -378,7 +530,7 @@ S32 LLTextureEntry::setTexGen(U8 tex_gen) mMediaFlags |= tex_gen; return TEM_CHANGE_TEXTURE; } - return 0; + return TEM_CHANGE_NONE; } S32 LLTextureEntry::setGlow(F32 glow) @@ -388,5 +540,115 @@ S32 LLTextureEntry::setGlow(F32 glow) mGlow = glow; return TEM_CHANGE_TEXTURE; } - return 0; + return TEM_CHANGE_NONE; +} + +void LLTextureEntry::setMediaData(const LLMediaEntry &media_entry) +{ + mMediaFlags |= MF_HAS_MEDIA; + if (NULL != mMediaEntry) + { + delete mMediaEntry; + } + mMediaEntry = new LLMediaEntry(media_entry); +} + +bool LLTextureEntry::updateMediaData(const LLSD& media_data) +{ + if (media_data.isUndefined()) + { + // clear the media data + clearMediaData(); + return false; + } + else { + mMediaFlags |= MF_HAS_MEDIA; + if (mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + // *NOTE: this will *clobber* all of the fields in mMediaEntry + // with whatever fields are present (or not present) in media_data! + mMediaEntry->fromLLSD(media_data); + return true; + } +} + +void LLTextureEntry::clearMediaData() +{ + mMediaFlags &= ~MF_HAS_MEDIA; + if (mMediaEntry != NULL) { + delete mMediaEntry; + } + mMediaEntry = NULL; +} + +void LLTextureEntry::mergeIntoMediaData(const LLSD& media_fields) +{ + mMediaFlags |= MF_HAS_MEDIA; + if (mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + // *NOTE: this will *merge* the data in media_fields + // with the data in our media entry + mMediaEntry->mergeFromLLSD(media_fields); +} + +//static +std::string LLTextureEntry::touchMediaVersionString(const std::string &in_version, const LLUUID &agent_id) +{ + // XXX TODO: make media version string binary (base64-encoded?) + // Media "URL" is a representation of a version and the last-touched agent + // x-mv:nnnnn/agent-id + // where "nnnnn" is version number + // *NOTE: not the most efficient code in the world... + U32 current_version = getVersionFromMediaVersionString(in_version) + 1; + const size_t MAX_VERSION_LEN = 10; // 2^32 fits in 10 decimal digits + char buf[MAX_VERSION_LEN+1]; + snprintf(buf, (int)MAX_VERSION_LEN+1, "%0*u", (int)MAX_VERSION_LEN, current_version); // added int cast to fix warning/breakage on mac. + return MEDIA_VERSION_STRING_PREFIX + buf + "/" + agent_id.asString(); +} + +//static +U32 LLTextureEntry::getVersionFromMediaVersionString(const std::string &version_string) +{ + U32 version = 0; + if (!version_string.empty()) + { + size_t found = version_string.find(MEDIA_VERSION_STRING_PREFIX); + if (found != std::string::npos) + { + found = version_string.find_first_of("/", found); + std::string v = version_string.substr(MEDIA_VERSION_STRING_PREFIX.length(), found); + version = strtoul(v.c_str(),NULL,10); + } + } + return version; +} + +//static +LLUUID LLTextureEntry::getAgentIDFromMediaVersionString(const std::string &version_string) +{ + LLUUID id; + if (!version_string.empty()) + { + size_t found = version_string.find(MEDIA_VERSION_STRING_PREFIX); + if (found != std::string::npos) + { + found = version_string.find_first_of("/", found); + if (found != std::string::npos) + { + std::string v = version_string.substr(found + 1); + id.set(v); + } + } + } + return id; +} + +//static +bool LLTextureEntry::isMediaVersionString(const std::string &version_string) +{ + return std::string::npos != version_string.find(MEDIA_VERSION_STRING_PREFIX); } diff --git a/linden/indra/llprimitive/lltextureentry.h b/linden/indra/llprimitive/lltextureentry.h old mode 100644 new mode 100755 index c562545fc..e70673ea2 --- a/linden/indra/llprimitive/lltextureentry.h +++ b/linden/indra/llprimitive/lltextureentry.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -37,9 +37,13 @@ #include "v4color.h" #include "llsd.h" +// These bits are used while unpacking TEM messages to tell which aspects of +// the texture entry changed. +const S32 TEM_CHANGE_NONE = 0x0; const S32 TEM_CHANGE_COLOR = 0x1; const S32 TEM_CHANGE_TEXTURE = 0x2; -const S32 TEM_INVALID = 0x4; +const S32 TEM_CHANGE_MEDIA = 0x4; +const S32 TEM_INVALID = 0x8; const S32 TEM_BUMPMAP_COUNT = 32; @@ -64,10 +68,13 @@ const S32 TEM_MEDIA_MASK = 0x01; const S32 TEM_TEX_GEN_MASK = 0x06; const S32 TEM_TEX_GEN_SHIFT = 1; +// forward declarations +class LLMediaEntry; class LLTextureEntry { public: + static LLTextureEntry* newTextureEntry(); typedef enum e_texgen { @@ -82,14 +89,18 @@ class LLTextureEntry LLTextureEntry(const LLTextureEntry &rhs); LLTextureEntry &operator=(const LLTextureEntry &rhs); - ~LLTextureEntry(); + virtual ~LLTextureEntry(); bool operator==(const LLTextureEntry &rhs) const; bool operator!=(const LLTextureEntry &rhs) const; LLSD asLLSD() const; + void asLLSD(LLSD& sd) const; operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); + bool fromLLSD(const LLSD& sd); + + virtual LLTextureEntry* newBlank() const; + virtual LLTextureEntry* newCopy() const; void init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump); @@ -99,7 +110,11 @@ class LLTextureEntry S32 setColor(const LLColor3 &color); S32 setAlpha(const F32 alpha); S32 setScale(F32 s, F32 t); + S32 setScaleS(F32 s); + S32 setScaleT(F32 t); S32 setOffset(F32 s, F32 t); + S32 setOffsetS(F32 s); + S32 setOffsetT(F32 t); S32 setRotation(F32 theta); S32 setBumpmap(U8 bump); @@ -113,7 +128,7 @@ class LLTextureEntry S32 setMediaTexGen(U8 media); S32 setGlow(F32 glow); - const LLUUID &getID() const { return mID; } + virtual const LLUUID &getID() const { return mID; } const LLColor4 &getColor() const { return mColor; } void getScale(F32 *s, F32 *t) const { *s = mScaleS; *t = mScaleT; } void getOffset(F32 *s, F32 *t) const { *s = mOffsetS; *t = mOffsetT; } @@ -130,9 +145,37 @@ class LLTextureEntry U8 getTexGen() const { return mMediaFlags & TEM_TEX_GEN_MASK; } U8 getMediaTexGen() const { return mMediaFlags; } F32 getGlow() const { return mGlow; } + + // *NOTE: it is possible for hasMedia() to return true, but getMediaData() to return NULL. + // CONVERSELY, it is also possible for hasMedia() to return false, but getMediaData() + // to NOT return NULL. + bool hasMedia() const { return (bool)(mMediaFlags & MF_HAS_MEDIA); } + LLMediaEntry* getMediaData() const { return mMediaEntry; } + + // Completely change the media data on this texture entry. + void setMediaData(const LLMediaEntry &media_entry); + // Returns true if media data was updated, false if it was cleared + bool updateMediaData(const LLSD& media_data); + // Clears media data, and sets the media flags bit to 0 + void clearMediaData(); + // Merges the given LLSD of media fields with this media entry. + // Only those fields that are set that match the keys in + // LLMediaEntry will be affected. If no fields are set or if + // the LLSD is undefined, this is a no-op. + void mergeIntoMediaData(const LLSD& media_fields); + + // Takes a media version string (an empty string or a previously-returned string) + // and returns a "touched" string, touched by agent_id + static std::string touchMediaVersionString(const std::string &in_version, const LLUUID &agent_id); + // Given a media version string, return the version + static U32 getVersionFromMediaVersionString(const std::string &version_string); + // Given a media version string, return the UUID of the agent + static LLUUID getAgentIDFromMediaVersionString(const std::string &version_string); + // Return whether or not the given string is actually a media version + static bool isMediaVersionString(const std::string &version_string); // Media flags - enum { MF_NONE = 0x0, MF_WEB_PAGE = 0x1 }; + enum { MF_NONE = 0x0, MF_HAS_MEDIA = 0x1 }; public: F32 mScaleS; // S, T offset @@ -142,6 +185,14 @@ class LLTextureEntry F32 mRotation; // anti-clockwise rotation in rad about the bottom left corner static const LLTextureEntry null; + + // LLSD key defines + static const char* OBJECT_ID_KEY; + static const char* OBJECT_MEDIA_DATA_KEY; + static const char* MEDIA_VERSION_KEY; + static const char* TEXTURE_INDEX_KEY; + static const char* TEXTURE_MEDIA_DATA_KEY; + protected: LLUUID mID; // Texture GUID LLColor4 mColor; @@ -149,6 +200,9 @@ class LLTextureEntry U8 mMediaFlags; // replace with web page, movie, etc. F32 mGlow; + // Note the media data is not sent via the same message structure as the rest of the TE + LLMediaEntry* mMediaEntry; // The media data for the face + // NOTE: when adding new data to this class, in addition to adding it to the serializers asLLSD/fromLLSD and the // message packers (e.g. LLPrimitive::packTEMessage) you must also implement its copy in LLPrimitive::copyTEs() diff --git a/linden/indra/llprimitive/material_codes.cpp b/linden/indra/llprimitive/material_codes.cpp new file mode 100755 index 000000000..8eb2ae77e --- /dev/null +++ b/linden/indra/llprimitive/material_codes.cpp @@ -0,0 +1,46 @@ +/** + * @file material_codes.cpp + * @brief Material_codes definitions + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "material_codes.h" + +#include "lluuid.h" + +const LLUUID LL_DEFAULT_STONE_UUID("87c5765b-aa26-43eb-b8c6-c09a1ca6208e"); +const LLUUID LL_DEFAULT_METAL_UUID("6f3c53e9-ba60-4010-8f3e-30f51a762476"); +const LLUUID LL_DEFAULT_GLASS_UUID("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); +const LLUUID LL_DEFAULT_WOOD_UUID("89556747-24cb-43ed-920b-47caed15465f"); +const LLUUID LL_DEFAULT_FLESH_UUID("80736669-e4b9-450e-8890-d5169f988a50"); +const LLUUID LL_DEFAULT_PLASTIC_UUID("304fcb4e-7d33-4339-ba80-76d3d22dc11a"); +const LLUUID LL_DEFAULT_RUBBER_UUID("9fae0bc5-666d-477e-9f70-84e8556ec867"); +const LLUUID LL_DEFAULT_LIGHT_UUID("00000000-0000-0000-0000-000000000000"); diff --git a/linden/indra/llprimitive/material_codes.h b/linden/indra/llprimitive/material_codes.h index ed159bc7d..c63f29577 100644 --- a/linden/indra/llprimitive/material_codes.h +++ b/linden/indra/llprimitive/material_codes.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2000&license=viewergpl$ * - * Copyright (c) 2000-2009, Linden Research, Inc. + * Copyright (c) 2000-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -33,7 +33,7 @@ #ifndef LL_MATERIAL_CODES_H #define LL_MATERIAL_CODES_H -#include "lluuid.h" +class LLUUID; // material types const U8 LL_MCODE_STONE = 0; @@ -47,13 +47,14 @@ const U8 LL_MCODE_LIGHT = 7; const U8 LL_MCODE_END = 8; const U8 LL_MCODE_MASK = 0x0F; -extern LLUUID const LL_DEFAULT_STONE_UUID; -extern LLUUID const LL_DEFAULT_METAL_UUID; -extern LLUUID const LL_DEFAULT_GLASS_UUID; -extern LLUUID const LL_DEFAULT_WOOD_UUID; -extern LLUUID const LL_DEFAULT_FLESH_UUID; -extern LLUUID const LL_DEFAULT_PLASTIC_UUID; -extern LLUUID const LL_DEFAULT_RUBBER_UUID; -extern LLUUID const LL_DEFAULT_LIGHT_UUID; +// *NOTE: Define these in .cpp file to reduce duplicate instances +extern const LLUUID LL_DEFAULT_STONE_UUID; +extern const LLUUID LL_DEFAULT_METAL_UUID; +extern const LLUUID LL_DEFAULT_GLASS_UUID; +extern const LLUUID LL_DEFAULT_WOOD_UUID; +extern const LLUUID LL_DEFAULT_FLESH_UUID; +extern const LLUUID LL_DEFAULT_PLASTIC_UUID; +extern const LLUUID LL_DEFAULT_RUBBER_UUID; +extern const LLUUID LL_DEFAULT_LIGHT_UUID; #endif diff --git a/linden/indra/llprimitive/tests/llmediaentry_test.cpp b/linden/indra/llprimitive/tests/llmediaentry_test.cpp new file mode 100755 index 000000000..89f778d38 --- /dev/null +++ b/linden/indra/llprimitive/tests/llmediaentry_test.cpp @@ -0,0 +1,508 @@ +/** + * @file llmediaentry_test.cpp + * @brief llmediaentry unit tests + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lltut.h" +#if LL_WINDOWS +#pragma warning (push) +#pragma warning (disable : 4702) // boost::lexical_cast generates this warning +#endif +#include <boost/lexical_cast.hpp> +#if LL_WINDOWS +#pragma warning (pop) +#endif +#include "llstring.h" +#include "llsdutil.h" +#include "llsdserialize.h" + +#include "../llmediaentry.h" +#include "lllslconstants.h" + +#define DEFAULT_MEDIA_ENTRY "<llsd>\n\ + <map>\n\ + <key>alt_image_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_loop</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_play</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_scale</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_zoom</key>\n\ + <boolean>0</boolean>\n\ + <key>controls</key>\n\ + <integer>0</integer>\n\ + <key>current_url</key>\n\ + <string />\n\ + <key>first_click_interact</key>\n\ + <boolean>0</boolean>\n\ + <key>height_pixels</key>\n\ + <integer>0</integer>\n\ + <key>home_url</key>\n\ + <string />\n\ + <key>perms_control</key>\n\ + <integer>7</integer>\n\ + <key>perms_interact</key>\n\ + <integer>7</integer>\n\ + <key>whitelist_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>width_pixels</key>\n\ + <integer>0</integer>\n\ + </map>\n\ + </llsd>" + +#define EMPTY_MEDIA_ENTRY "<llsd>\n\ + <map>\n\ + <key>alt_image_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_loop</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_play</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_scale</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_zoom</key>\n\ + <boolean>0</boolean>\n\ + <key>controls</key>\n\ + <integer>0</integer>\n\ + <key>current_url</key>\n\ + <string />\n\ + <key>first_click_interact</key>\n\ + <boolean>0</boolean>\n\ + <key>height_pixels</key>\n\ + <integer>0</integer>\n\ + <key>home_url</key>\n\ + <string />\n\ + <key>perms_control</key>\n\ + <integer>0</integer>\n\ + <key>perms_interact</key>\n\ + <integer>0</integer>\n\ + <key>whitelist_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>width_pixels</key>\n\ + <integer>0</integer>\n\ + </map>\n\ + </llsd>" + +#define PARTIAL_MEDIA_ENTRY(CURRENT_URL) "<llsd>\n\ + <map>\n\ + <key>alt_image_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_loop</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_play</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_scale</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_zoom</key>\n\ + <boolean>0</boolean>\n\ + <key>controls</key>\n\ + <integer>0</integer>\n\ + <key>current_url</key>\n\ + <string>" CURRENT_URL "</string>\n\ + <key>first_click_interact</key>\n\ + <boolean>0</boolean>\n\ + <key>height_pixels</key>\n\ + <integer>0</integer>\n\ + <key>home_url</key>\n\ + <string />\n\ + <key>perms_control</key>\n\ + <integer>0</integer>\n\ + <key>perms_interact</key>\n\ + <integer>0</integer>\n\ + <key>whitelist_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>width_pixels</key>\n\ + <integer>0</integer>\n\ + </map>\n\ + </llsd>" + +namespace tut +{ + // this is fixture data that gets created before each test and destroyed + // after each test. this is where we put all of the setup/takedown code + // and data needed for each test. + struct MediaEntry_test + { + MediaEntry_test() { + emptyMediaEntryStr = EMPTY_MEDIA_ENTRY; + std::istringstream e(EMPTY_MEDIA_ENTRY); + LLSDSerialize::fromXML(emptyMediaEntryLLSD, e); + defaultMediaEntryStr = DEFAULT_MEDIA_ENTRY; + std::istringstream d(DEFAULT_MEDIA_ENTRY); + LLSDSerialize::fromXML(defaultMediaEntryLLSD, d); + } + std::string emptyMediaEntryStr; + LLSD emptyMediaEntryLLSD; + std::string defaultMediaEntryStr; + LLSD defaultMediaEntryLLSD; + }; + + typedef test_group<MediaEntry_test, 55> factory; + typedef factory::object object; +} + + +namespace +{ + // this is for naming our tests to make pretty output + tut::factory tf("MediaEntry Test"); +} + +namespace tut +{ + void ensure_llsd_equals(const std::string& msg, const LLSD& expected, const LLSD& actual) + { + if (!llsd_equals(expected, actual)) + { + std::string message = msg; + message += ": actual: "; + message += ll_pretty_print_sd(actual); + message += "\n expected: "; + message += ll_pretty_print_sd(expected); + message += "\n"; + ensure(message, false); + } + } + + void ensure_string_equals(const std::string& msg, const std::string& expected, const std::string& actual) + { + if ( expected != actual ) + { + std::string message = msg; + message += ": actual: "; + message += actual; + message += "\n expected: "; + message += expected; + message += "\n"; + ensure(message, false); + } + } + + void set_whitelist(LLMediaEntry &entry, const char *str) + { + std::vector<std::string> tokens; + LLStringUtil::getTokens(std::string(str), tokens, ","); + entry.setWhiteList(tokens); + } + + void whitelist_test(int num, bool enable, const char *whitelist, const char *candidate_url, bool expected_pass) + { + std::string message = "Whitelist test " + boost::lexical_cast<std::string>(num); + LLMediaEntry entry; + entry.setWhiteListEnable(enable); + set_whitelist(entry, whitelist); + bool passed_whitelist = entry.checkCandidateUrl(candidate_url); + if (passed_whitelist != expected_pass) + { + message += " failed: expected "; + message += (expected_pass) ? "" : "NOT "; + message += "to match\nwhitelist = "; + message += whitelist; + message += "\ncandidate_url = "; + message += candidate_url; + } + ensure(message, expected_pass == passed_whitelist); + } + + void whitelist_test(int num, const char *whitelist, const char *candidate_url, bool expected_pass) + { + whitelist_test(num, true, whitelist, candidate_url, expected_pass); + } + void whitelist_test(int num, const char *whitelist, const char *candidate_url) + { + whitelist_test(num, true, whitelist, candidate_url, true); + } + + template<> template<> + void object::test<1>() + { + set_test_name("Test LLMediaEntry Instantiation"); + LLMediaEntry entry; + ensure_llsd_equals(get_test_name() + " failed", defaultMediaEntryLLSD, entry.asLLSD()); + } + + template<> template<> + void object::test<2>() + { + set_test_name("Test LLMediaEntry Instantiation from LLSD"); + LLMediaEntry entry; + LLSD sd; + entry.fromLLSD(sd); + ensure_llsd_equals(get_test_name() + " failed", emptyMediaEntryLLSD, entry.asLLSD()); + } + + template<> template<> + void object::test<3>() + { + set_test_name("Test LLMediaEntry Partial Instantiation from LLSD"); + LLMediaEntry entry; + LLSD sd; + sd[LLMediaEntry::CURRENT_URL_KEY] = "http://www.example.com"; + entry.fromLLSD(sd); + LLSD golden; + std::istringstream p(PARTIAL_MEDIA_ENTRY("http://www.example.com")); + LLSDSerialize::fromXML(golden,p); + ensure_llsd_equals(get_test_name() + " failed", golden, entry.asLLSD()); + } + + template<> template<> + void object::test<4>() + { + set_test_name("Test LLMediaEntry::asLLSD()"); + LLMediaEntry entry; + LLSD sd; + // Put some cruft in the LLSD + sd[LLMediaEntry::CURRENT_URL_KEY] = "http://www.example.com"; + LLSD whitelist; + whitelist.append("*.example.com"); + sd[LLMediaEntry::WHITELIST_KEY] = whitelist; + entry.asLLSD(sd); + ensure_llsd_equals(get_test_name() + " failed", defaultMediaEntryLLSD, sd); + } + + + template<> template<> + void object::test<5>() + { + set_test_name("Test LLMediaEntry::asLLSD() -> LLMediaEntry::fromLLSD()"); + LLMediaEntry entry1, entry2; + // Add a whitelist to entry2 + std::vector<std::string> whitelist; + whitelist.push_back("*.example.com"); + entry2.setWhiteList(whitelist); + // Render entry1 (which has no whitelist) as an LLSD + LLSD sd; + entry1.asLLSD(sd); + // "read" that LLSD into entry 2 + entry2.fromLLSD(sd); + ensure_llsd_equals(get_test_name() + " failed", defaultMediaEntryLLSD, entry2.asLLSD()); + } + + // limit tests + const char *URL_OK = "http://www.example.com"; + const char *URL_TOO_BIG = "http://www.example.com.qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; + + template<> template<> + void object::test<6>() + { + set_test_name("Test Limits on setting current URL"); + LLMediaEntry entry; + U32 status = entry.setCurrentURL(URL_OK); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_OK); + status = entry.setCurrentURL(URL_TOO_BIG); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_BOUNDS_ERROR); + } + + template<> template<> + void object::test<7>() + { + set_test_name("Test Limits on setting home URL"); + LLMediaEntry entry; + U32 status = entry.setHomeURL(URL_OK); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_OK); + status = entry.setHomeURL(URL_TOO_BIG); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_BOUNDS_ERROR); + } + + template<> template<> + void object::test<8>() + { + set_test_name("Test Limits on setting whitelist"); + + // Test a valid list + LLMediaEntry entry; + std::vector<std::string> whitelist; + whitelist.push_back(std::string(URL_OK)); + S32 status = entry.setWhiteList(whitelist); + ensure(get_test_name() + " invalid result", status == LSL_STATUS_OK); + ensure(get_test_name() + " failed", whitelist == entry.getWhiteList()); + } + + template<> template<> + void object::test<9>() + { + set_test_name("Test Limits on setting whitelist too big"); + + // Test an invalid list + LLMediaEntry entry; + std::vector<std::string> whitelist, empty; + whitelist.push_back(std::string(URL_OK)); + whitelist.push_back(std::string(URL_TOO_BIG)); + S32 status = entry.setWhiteList(whitelist); + ensure(get_test_name() + " invalid result", status == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", empty == entry.getWhiteList()); + } + + template<> template<> + void object::test<10>() + { + set_test_name("Test Limits on setting whitelist too many"); + + // Test an invalid list + LLMediaEntry entry; + std::vector<std::string> whitelist, empty; + for (int i=0; i < LLMediaEntry::MAX_WHITELIST_SIZE+1; i++) { + whitelist.push_back("Q"); + } + S32 status = entry.setWhiteList(whitelist); + ensure(get_test_name() + " invalid result", status == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", empty == entry.getWhiteList()); + } + + template<> template<> + void object::test<11>() + { + set_test_name("Test to make sure both setWhiteList() functions behave the same"); + + // Test a valid list + std::vector<std::string> whitelist, empty; + LLSD whitelist_llsd; + whitelist.push_back(std::string(URL_OK)); + whitelist_llsd.append(std::string(URL_OK)); + LLMediaEntry entry1, entry2; + ensure(get_test_name() + " setWhiteList(s) don't match", + entry1.setWhiteList(whitelist) == LSL_STATUS_OK && + entry2.setWhiteList(whitelist_llsd)== LSL_STATUS_OK ); + ensure(get_test_name() + " failed", + entry1.getWhiteList() == entry2.getWhiteList()); + } + + template<> template<> + void object::test<12>() + { + set_test_name("Test to make sure both setWhiteList() functions behave the same"); + + // Test an invalid list + std::vector<std::string> whitelist, empty; + LLSD whitelist_llsd; + whitelist.push_back(std::string(URL_OK)); + whitelist.push_back(std::string(URL_TOO_BIG)); + whitelist_llsd.append(std::string(URL_OK)); + whitelist_llsd.append(std::string(URL_TOO_BIG)); + LLMediaEntry entry1, entry2; + ensure(get_test_name() + " setWhiteList(s) don't match", + entry1.setWhiteList(whitelist) == LSL_STATUS_BOUNDS_ERROR && + entry2.setWhiteList(whitelist_llsd) == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", + empty == entry1.getWhiteList() && + empty == entry2.getWhiteList()); + } + + template<> template<> + void object::test<13>() + { + set_test_name("Test to make sure both setWhiteList() functions behave the same"); + + // Test an invalid list, too many + std::vector<std::string> whitelist, empty; + LLSD whitelist_llsd; + for (int i=0; i < LLMediaEntry::MAX_WHITELIST_SIZE+1; i++) { + whitelist.push_back("Q"); + whitelist_llsd.append("Q"); + } + LLMediaEntry entry1, entry2; + ensure(get_test_name() + " invalid result", + entry1.setWhiteList(whitelist) == LSL_STATUS_BOUNDS_ERROR && + entry2.setWhiteList(whitelist_llsd) == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", + empty == entry1.getWhiteList() && + empty == entry2.getWhiteList()); + } + + template<> template<> + void object::test<14>() + { + // Whitelist check tests + int n=0; + + // Check the "empty whitelist" case + whitelist_test(++n, "", "http://www.example.com", true); + + // Check the "missing scheme" case + whitelist_test(++n, "www.example.com", "http://www.example.com", true); + + // Check the "exactly the same" case + whitelist_test(++n, "http://example.com", "http://example.com", true); + + // Check the enable flag + whitelist_test(++n, false, "www.example.com", "http://www.secondlife.com", true); + whitelist_test(++n, true, "www.example.com", "http://www.secondlife.com", false); + + // Check permutations of trailing slash: + whitelist_test(++n, "http://www.example.com", "http://www.example.com/", true); + whitelist_test(++n, "http://www.example.com/", "http://www.example.com/", true); + whitelist_test(++n, "http://www.example.com/", "http://www.example.com", false); + whitelist_test(++n, "http://www.example.com", "http://www.example.com/foobar", true); + whitelist_test(++n, "http://www.example.com/", "http://www.example.com/foobar", false); + + + // More cases... + whitelist_test(++n, "http://example.com", "http://example.com/wiki", true); + whitelist_test(++n, "www.example.com", "http://www.example.com/help", true); + whitelist_test(++n, "http://www.example.com", "http://wwwexample.com", false); + whitelist_test(++n, "http://www.example.com", "http://www.example.com/wiki", true); + whitelist_test(++n, "example.com", "http://wwwexample.com", false); + whitelist_test(++n, "http://www.example.com/", "http://www.amazon.com/wiki", false); + whitelist_test(++n, "www.example.com", "http://www.amazon.com", false); + + // regexp cases + whitelist_test(++n, "*.example.com", "http://www.example.com", true); + whitelist_test(++n, "*.example.com", "http://www.amazon.com", false); + whitelist_test(++n, "*.example.com", "http://www.example.com/foo/bar", true); + whitelist_test(++n, "*.example.com", "http:/example.com/foo/bar", false); + whitelist_test(++n, "*example.com", "http://example.com/foo/bar", true); + whitelist_test(++n, "*example.com", "http://my.virus.com/foo/bar?example.com", false); + whitelist_test(++n, "example.com", "http://my.virus.com/foo/bar?example.com", false); + whitelist_test(++n, "*example.com", "http://my.virus.com/foo/bar?*example.com", false); + whitelist_test(++n, "http://*example.com", "http://www.example.com", true); + whitelist_test(++n, "http://*.example.com", "http://www.example.com", true); + whitelist_test(++n, "http://*.e$?^.com", "http://www.e$?^.com", true); + whitelist_test(++n, "*.example.com/foo/bar", "http://www.example.com/", false); + whitelist_test(++n, "*.example.com/foo/bar", "http://example.com/foo/bar", false); + whitelist_test(++n, "http://*.example.com/foo/bar", "http://www.example.com", false); + whitelist_test(++n, "http://*.example.com", "https://www.example.com", false); + whitelist_test(++n, "http*://*.example.com", "rtsp://www.example.com", false); + whitelist_test(++n, "http*://*.example.com", "https://www.example.com", true); + whitelist_test(++n, "example.com", "http://www.example.com", false); + whitelist_test(++n, "www.example.com", "http://www.example.com:80", false); + whitelist_test(++n, "www.example.com", "http://www.example.com", true); + whitelist_test(++n, "www.example.com/", "http://www.example.com", false); + whitelist_test(++n, "www.example.com/foo/bar/*", "http://www.example.com/foo/bar/baz", true); + + // Path only + whitelist_test(++n, "/foo/*/baz", "http://www.example.com/foo/bar/baz", true); + whitelist_test(++n, "/foo/*/baz", "http://www.example.com/foo/bar/", false); + } + +} + diff --git a/linden/indra/llprimitive/tests/llmessagesystem_stub.cpp b/linden/indra/llprimitive/tests/llmessagesystem_stub.cpp new file mode 100755 index 000000000..37a61de12 --- /dev/null +++ b/linden/indra/llprimitive/tests/llmessagesystem_stub.cpp @@ -0,0 +1,53 @@ +/** + * @file llmessagesystem_stub.cpp + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +char * _PREHASH_TextureEntry; + +S32 LLMessageSystem::getSizeFast(char const*, char const*) const +{ + return 0; +} + +S32 LLMessageSystem::getSizeFast(char const*, int, char const*) const +{ + return 0; +} + +void LLMessageSystem::getBinaryDataFast(char const*, char const*, void*, int, int, int) +{ +} + +void LLMessageSystem::addBinaryDataFast(char const*, void const*, int) +{ +} + diff --git a/linden/indra/llprimitive/tests/llprimitive_test.cpp b/linden/indra/llprimitive/tests/llprimitive_test.cpp new file mode 100755 index 000000000..c923442a6 --- /dev/null +++ b/linden/indra/llprimitive/tests/llprimitive_test.cpp @@ -0,0 +1,237 @@ +/** + * @file llprimitive_test.cpp + * @brief llprimitive tests + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "../test/lltut.h" + +#include "../llprimitive.h" + +#include "../../llmath/llvolumemgr.h" + +class DummyVolumeMgr : public LLVolumeMgr +{ +public: + DummyVolumeMgr() : LLVolumeMgr(), mVolumeTest(NULL), mCurrDetailTest(0) {} + ~DummyVolumeMgr() + { + } + + + virtual LLVolume *refVolume(const LLVolumeParams &volume_params, const S32 detail) + { + if (mVolumeTest.isNull() || volume_params != mCurrParamsTest || detail != mCurrDetailTest) + { + F32 volume_detail = LLVolumeLODGroup::getVolumeScaleFromDetail(detail); + mVolumeTest = new LLVolume(volume_params, volume_detail, FALSE, FALSE); + mCurrParamsTest = volume_params; + mCurrDetailTest = detail; + return mVolumeTest; + } + else + { + return mVolumeTest; + } + } + + virtual void unrefVolume(LLVolume *volumep) + { + if (mVolumeTest == volumep) + { + mVolumeTest = NULL; + } + } + +private: + LLPointer<LLVolume> mVolumeTest; + LLVolumeParams mCurrParamsTest; + S32 mCurrDetailTest; +}; + +class PRIMITIVE_TEST_SETUP +{ +public: + PRIMITIVE_TEST_SETUP() + { + volume_manager_test = new DummyVolumeMgr(); + LLPrimitive::setVolumeManager(volume_manager_test); + } + + ~PRIMITIVE_TEST_SETUP() + { + LLPrimitive::cleanupVolumeManager(); + } + DummyVolumeMgr * volume_manager_test; +}; + +namespace tut +{ + struct llprimitive + { + PRIMITIVE_TEST_SETUP setup_class; + }; + + typedef test_group<llprimitive> llprimitive_t; + typedef llprimitive_t::object llprimitive_object_t; + tut::llprimitive_t tut_llprimitive("llprimitive"); + + template<> template<> + void llprimitive_object_t::test<1>() + { + set_test_name("Test LLPrimitive Instantiation"); + LLPrimitive test; + } + + template<> template<> + void llprimitive_object_t::test<2>() + { + set_test_name("Test LLPrimitive PCode setter and getter."); + LLPrimitive test; + ensure_equals(test.getPCode(), 0); + LLPCode code = 1; + test.setPCode(code); + ensure_equals(test.getPCode(), code); + } + + template<> template<> + void llprimitive_object_t::test<3>() + { + set_test_name("Test llprimitive constructor and initer."); + LLPCode code = 1; + LLPrimitive primitive; + primitive.init_primitive(code); + ensure_equals(primitive.getPCode(), code); + } + + template<> template<> + void llprimitive_object_t::test<4>() + { + set_test_name("Test Static llprimitive constructor and initer."); + LLPCode code = 1; + LLPrimitive * primitive = LLPrimitive::createPrimitive(code); + ensure(primitive != NULL); + ensure_equals(primitive->getPCode(), code); + } + + template<> template<> + void llprimitive_object_t::test<5>() + { + set_test_name("Test setVolume creation of new unique volume."); + LLPrimitive primitive; + LLVolumeParams params; + + // Make sure volume starts off null + ensure(primitive.getVolume() == NULL); + + // Make sure we have no texture entries before setting the volume + ensure_equals(primitive.getNumTEs(), 0); + + // Test that GEOMETRY has not been flagged as changed. + ensure(!primitive.isChanged(LLXform::GEOMETRY)); + + // Make sure setVolume returns true + ensure(primitive.setVolume(params, 0, true) == TRUE); + LLVolume* new_volume = primitive.getVolume(); + + // make sure new volume was actually created + ensure(new_volume != NULL); + + // Make sure that now that we've set the volume we have texture entries + ensure_not_equals(primitive.getNumTEs(), 0); + + // Make sure that the number of texture entries equals the number of faces in the volume (should be 6) + ensure_equals(new_volume->getNumFaces(), 6); + ensure_equals(primitive.getNumTEs(), new_volume->getNumFaces()); + + // Test that GEOMETRY has been flagged as changed. + ensure(primitive.isChanged(LLXform::GEOMETRY)); + + // Run it twice to make sure it doesn't create a different one if params are the same + ensure(primitive.setVolume(params, 0, true) == FALSE); + ensure(new_volume == primitive.getVolume()); + + // Change the param definition and try setting it again. + params.setRevolutions(4); + ensure(primitive.setVolume(params, 0, true) == TRUE); + + // Ensure that we now have a different volume + ensure(new_volume != primitive.getVolume()); + } + + template<> template<> + void llprimitive_object_t::test<6>() + { + set_test_name("Test setVolume creation of new NOT-unique volume."); + LLPrimitive primitive; + LLVolumeParams params; + + // Make sure volume starts off null + ensure(primitive.getVolume() == NULL); + + // Make sure we have no texture entries before setting the volume + ensure_equals(primitive.getNumTEs(), 0); + + // Test that GEOMETRY has not been flagged as changed. + ensure(!primitive.isChanged(LLXform::GEOMETRY)); + + // Make sure setVolume returns true + ensure(primitive.setVolume(params, 0, false) == TRUE); + + LLVolume* new_volume = primitive.getVolume(); + + // make sure new volume was actually created + ensure(new_volume != NULL); + + // Make sure that now that we've set the volume we have texture entries + ensure_not_equals(primitive.getNumTEs(), 0); + + // Make sure that the number of texture entries equals the number of faces in the volume (should be 6) + ensure_equals(new_volume->getNumFaces(), 6); + ensure_equals(primitive.getNumTEs(), new_volume->getNumFaces()); + + // Test that GEOMETRY has been flagged as changed. + ensure(primitive.isChanged(LLXform::GEOMETRY)); + + // Run it twice to make sure it doesn't create a different one if params are the same + ensure(primitive.setVolume(params, 0, false) == FALSE); + ensure(new_volume == primitive.getVolume()); + + // Change the param definition and try setting it again. + params.setRevolutions(4); + ensure(primitive.setVolume(params, 0, false) == TRUE); + + // Ensure that we now have a different volume + ensure(new_volume != primitive.getVolume()); + } +} + +#include "llmessagesystem_stub.cpp" diff --git a/linden/indra/llrender/llfontgl.cpp b/linden/indra/llrender/llfontgl.cpp index 5d3d6a7fd..7baec8159 100644 --- a/linden/indra/llrender/llfontgl.cpp +++ b/linden/indra/llrender/llfontgl.cpp @@ -42,6 +42,7 @@ #include "llrender.h" #include "v4color.h" #include "llstl.h" +#include "llfasttimer.h" const S32 BOLD_OFFSET = 1; diff --git a/linden/indra/llrender/llfontregistry.cpp b/linden/indra/llrender/llfontregistry.cpp index 9792a91de..c5923cdb0 100644 --- a/linden/indra/llrender/llfontregistry.cpp +++ b/linden/indra/llrender/llfontregistry.cpp @@ -442,7 +442,15 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) std::string font_path = local_path + *file_name_it; BOOL is_fallback = !is_first_found; F32 size_mult = (is_fallback ? 1 : match_desc->getSizeMult()); - F32 size = (F32)llround(point_size * size_mult); + if (gSavedSettings.getF32("FontSizeMultiplier") > 0) + { + size_mult *= gSavedSettings.getF32("FontSizeMultiplier"); + } + F32 size = (F32)(point_size * size_mult); + if (gSavedSettings.getBOOL("FontSizeRounding")) + { + size = (F32)llround(size); + } if (!fontp->loadFace(font_path, size, LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback)) { diff --git a/linden/indra/llrender/llgl.cpp b/linden/indra/llrender/llgl.cpp index 2e9b2bdeb..4a4ff1b93 100644 --- a/linden/indra/llrender/llgl.cpp +++ b/linden/indra/llrender/llgl.cpp @@ -547,8 +547,6 @@ void LLGLManager::shutdownGL() // these are used to turn software blending on. They appear in the Debug/Avatar menu // presence of vertex skinning/blending or vertex programs will set these to FALSE by default. -extern LLCPUInfo gSysCPU; - void LLGLManager::initExtensions() { #if LL_MESA_HEADLESS diff --git a/linden/indra/llui/CMakeLists.txt b/linden/indra/llui/CMakeLists.txt index a0f80b4d7..e6b3b636a 100644 --- a/linden/indra/llui/CMakeLists.txt +++ b/linden/indra/llui/CMakeLists.txt @@ -3,11 +3,9 @@ project(llui) include(00-Common) -include(LLAudio) include(LLCommon) include(LLImage) include(LLMath) -include(LLMedia) include(LLMessage) include(LLRender) include(LLWindow) @@ -15,11 +13,9 @@ include(LLVFS) include(LLXML) include_directories( - ${LLAUDIO_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} ${LLIMAGE_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} - ${LLMEDIA_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} @@ -141,3 +137,14 @@ set_source_files_properties(${llui_HEADER_FILES} list(APPEND llui_SOURCE_FILES ${llui_HEADER_FILES}) add_library (llui ${llui_SOURCE_FILES}) +# Libraries on which this library depends, needed for Linux builds +# Sort by high-level to low-level +target_link_libraries(llui + llrender + llwindow + llimage + llvfs # ugh, just for LLDir + llxml + llcommon # must be after llimage, llwindow, llrender + llmath + ) diff --git a/linden/indra/llui/llbutton.cpp b/linden/indra/llui/llbutton.cpp index 1a6c705ff..702e34e72 100644 --- a/linden/indra/llui/llbutton.cpp +++ b/linden/indra/llui/llbutton.cpp @@ -840,6 +840,11 @@ void LLButton::setColor(const LLColor4& color) setImageColor(color); } +void LLButton::setAlpha(F32 alpha) +{ + mImageColor.setAlpha(alpha); + mDisabledImageColor.setAlpha(alpha * 0.5f); +} void LLButton::setImageDisabled(LLPointer<LLUIImage> image) { diff --git a/linden/indra/llui/llbutton.h b/linden/indra/llui/llbutton.h index 724b77541..2174d952c 100644 --- a/linden/indra/llui/llbutton.h +++ b/linden/indra/llui/llbutton.h @@ -136,7 +136,8 @@ class LLButton void setImageColor(const std::string& color_control); void setImageColor(const LLColor4& c); - virtual void setColor(const LLColor4& c); + /*virtual*/ void setColor(const LLColor4& c); + /*virtual*/ void setAlpha(F32 alpha); void setImages(const std::string &image_name, const std::string &selected_name); void setDisabledImages(const std::string &image_name, const std::string &selected_name); diff --git a/linden/indra/llui/llfloater.cpp b/linden/indra/llui/llfloater.cpp index f6451a1c6..bb42ca34c 100644 --- a/linden/indra/llui/llfloater.cpp +++ b/linden/indra/llui/llfloater.cpp @@ -1459,9 +1459,9 @@ void LLFloater::draw() { if (hasFocus() && getDefaultButton()->getEnabled()) { - LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); // is this button a direct descendent and not a nested widget (e.g. checkbox)? - BOOL focus_is_child_button = dynamic_cast<LLButton*>(focus_ctrl) != NULL && focus_ctrl->getParent() == this; + BOOL focus_is_child_button = dynamic_cast<LLButton*>(focus_ctrl) != NULL && dynamic_cast<LLButton*>(focus_ctrl)->getParent() == this; // only enable default button when current focus is not a button getDefaultButton()->setBorderEnabled(!focus_is_child_button); } @@ -1481,7 +1481,7 @@ void LLFloater::draw() else { // draw children - LLView* focused_child = gFocusMgr.getKeyboardFocus(); + LLView* focused_child = dynamic_cast<LLView*>(gFocusMgr.getKeyboardFocus()); BOOL focused_child_visible = FALSE; if (focused_child && focused_child->getParent() == this) { @@ -2239,7 +2239,7 @@ BOOL LLFloaterView::allChildrenClosed() LLView* viewp = *it; LLFloater* floaterp = (LLFloater*)viewp; - if (floaterp->getVisible() && !floaterp->isDead() && floaterp->canClose()) + if (floaterp->getVisible() && !floaterp->isDead() && floaterp->isCloseable()) { return false; } diff --git a/linden/indra/llui/llfocusmgr.cpp b/linden/indra/llui/llfocusmgr.cpp index 661ffdd46..96b01b98f 100644 --- a/linden/indra/llui/llfocusmgr.cpp +++ b/linden/indra/llui/llfocusmgr.cpp @@ -38,6 +38,68 @@ const F32 FOCUS_FADE_TIME = 0.3f; +// NOTE: the LLFocusableElement implementation has been here from lluictrl.cpp. + +LLFocusableElement::LLFocusableElement() +: mFocusLostCallback(NULL), + mFocusReceivedCallback(NULL), + mFocusChangedCallback(NULL), + mFocusCallbackUserData(NULL) +{ +} + +// virtual +BOOL LLFocusableElement::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ + return FALSE; +} + +// virtual +BOOL LLFocusableElement::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) +{ + return FALSE; +} + +// virtual +LLFocusableElement::~LLFocusableElement() +{ +} + +void LLFocusableElement::onFocusReceived() +{ + if( mFocusReceivedCallback ) + { + mFocusReceivedCallback( this, mFocusCallbackUserData ); + } + if( mFocusChangedCallback ) + { + mFocusChangedCallback( this, mFocusCallbackUserData ); + } +} + +void LLFocusableElement::onFocusLost() +{ + if( mFocusLostCallback ) + { + mFocusLostCallback( this, mFocusCallbackUserData ); + } + + if( mFocusChangedCallback ) + { + mFocusChangedCallback( this, mFocusCallbackUserData ); + } +} + +BOOL LLFocusableElement::hasFocus() const +{ + return gFocusMgr.getKeyboardFocus() == this; +} + +void LLFocusableElement::setFocus(BOOL b) +{ +} + + LLFocusMgr gFocusMgr; LLFocusMgr::LLFocusMgr() @@ -87,11 +149,13 @@ void LLFocusMgr::releaseFocusIfNeeded( const LLView* view ) } -void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystrokes_only) +void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL keystrokes_only) { if (mLockedView && (new_focus == NULL || - (new_focus != mLockedView && !new_focus->hasAncestor(mLockedView)))) + (new_focus != mLockedView + && dynamic_cast<LLView*>(new_focus) + && !dynamic_cast<LLView*>(new_focus)->hasAncestor(mLockedView)))) { // don't allow focus to go to anything that is not the locked focus // or one of its descendants @@ -121,7 +185,8 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke mFocusTimer.reset(); #ifdef _DEBUG - mKeyboardFocusName = new_focus ? new_focus->getName() : std::string("none"); + LLUICtrl* focus_ctrl = dynamic_cast<LLUICtrl*>(new_focus); + mKeyboardFocusName = focus_ctrl ? focus_ctrl->getName() : std::string("none"); #endif // If we've got a default keyboard focus, and the caller is @@ -131,8 +196,8 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke mDefaultKeyboardFocus->setFocus(TRUE); } - LLView* focus_subtree = mKeyboardFocus; - LLView* viewp = mKeyboardFocus; + LLView* focus_subtree = dynamic_cast<LLView*>(mKeyboardFocus); + LLView* viewp = dynamic_cast<LLView*>(mKeyboardFocus); // find root-most focus root while(viewp) { @@ -146,7 +211,8 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke if (focus_subtree) { - mFocusHistory[focus_subtree->getHandle()] = mKeyboardFocus ? mKeyboardFocus->getHandle() : LLHandle<LLView>(); + LLView* focused_view = dynamic_cast<LLView*>(mKeyboardFocus); + mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle<LLView>(); } } @@ -160,7 +226,7 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke // Returns TRUE is parent or any descedent of parent has keyboard focus. BOOL LLFocusMgr::childHasKeyboardFocus(const LLView* parent ) const { - LLView* focus_view = mKeyboardFocus; + LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus); while( focus_view ) { if( focus_view == parent ) @@ -190,7 +256,7 @@ BOOL LLFocusMgr::childHasMouseCapture( const LLView* parent ) const return FALSE; } -void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLView* focus ) +void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* focus ) { // should be ok to unlock here, as you have to know the locked view // in order to unlock it @@ -313,7 +379,7 @@ void LLFocusMgr::removeTopCtrlWithoutCallback( const LLUICtrl* top_view ) void LLFocusMgr::lockFocus() { - mLockedView = mKeyboardFocus; + mLockedView = dynamic_cast<LLUICtrl*>(mKeyboardFocus); } void LLFocusMgr::unlockFocus() diff --git a/linden/indra/llui/llfocusmgr.h b/linden/indra/llui/llfocusmgr.h index aaeb25a87..88ede1aff 100644 --- a/linden/indra/llui/llfocusmgr.h +++ b/linden/indra/llui/llfocusmgr.h @@ -37,10 +37,39 @@ #include "llstring.h" #include "llframetimer.h" -#include "llview.h" +#include "llui.h" class LLUICtrl; class LLMouseHandler; +class LLView; + +class LLFocusableElement +{ + friend class LLFocusMgr; // allow access to focus change handlers +public: + LLFocusableElement(); + virtual ~LLFocusableElement(); + + virtual void setFocus( BOOL b ); + virtual BOOL hasFocus() const; + + void setFocusLostCallback(void (*cb)(LLFocusableElement* caller, void*), void* user_data = NULL) { mFocusLostCallback = cb; mFocusCallbackUserData = user_data; } + void setFocusReceivedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL) { mFocusReceivedCallback = cb; mFocusCallbackUserData = user_data; } + void setFocusChangedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL ) { mFocusChangedCallback = cb; mFocusCallbackUserData = user_data; } + + // These were brought up the hierarchy from LLView so that we don't have to use dynamic_cast when dealing with keyboard focus. + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + +protected: + virtual void onFocusReceived(); + virtual void onFocusLost(); + void (*mFocusLostCallback)( LLFocusableElement* caller, void* userdata ); + void (*mFocusReceivedCallback)( LLFocusableElement* ctrl, void* userdata ); + void (*mFocusChangedCallback)( LLFocusableElement* ctrl, void* userdata ); + void* mFocusCallbackUserData; +}; + class LLFocusMgr { @@ -55,11 +84,11 @@ class LLFocusMgr BOOL childHasMouseCapture( const LLView* parent ) const; // Keyboard Focus - void setKeyboardFocus(LLUICtrl* new_focus, BOOL lock = FALSE, BOOL keystrokes_only = FALSE); // new_focus = NULL to release the focus. - LLUICtrl* getKeyboardFocus() const { return mKeyboardFocus; } - LLUICtrl* getLastKeyboardFocus() const { return mLastKeyboardFocus; } + void setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock = FALSE, BOOL keystrokes_only = FALSE); // new_focus = NULL to release the focus. + LLFocusableElement* getKeyboardFocus() const { return mKeyboardFocus; } + LLFocusableElement* getLastKeyboardFocus() const { return mLastKeyboardFocus; } BOOL childHasKeyboardFocus( const LLView* parent ) const; - void removeKeyboardFocusWithoutCallback( const LLView* focus ); + void removeKeyboardFocusWithoutCallback( const LLFocusableElement* focus ); BOOL getKeystrokesOnly() { return mKeystrokesOnly; } void setKeystrokesOnly(BOOL keystrokes_only) { mKeystrokesOnly = keystrokes_only; } @@ -75,8 +104,8 @@ class LLFocusMgr // If setKeyboardFocus(NULL) is called, and there is a non-NULL default // keyboard focus view, focus goes there. JC - void setDefaultKeyboardFocus(LLUICtrl* default_focus) { mDefaultKeyboardFocus = default_focus; } - LLUICtrl* getDefaultKeyboardFocus() const { return mDefaultKeyboardFocus; } + void setDefaultKeyboardFocus(LLFocusableElement* default_focus) { mDefaultKeyboardFocus = default_focus; } + LLFocusableElement* getDefaultKeyboardFocus() const { return mDefaultKeyboardFocus; } // Top View @@ -98,9 +127,9 @@ class LLFocusMgr LLMouseHandler* mMouseCaptor; // Mouse events are premptively routed to this object // Keyboard Focus - LLUICtrl* mKeyboardFocus; // Keyboard events are preemptively routed to this object - LLUICtrl* mLastKeyboardFocus; // who last had focus - LLUICtrl* mDefaultKeyboardFocus; + LLFocusableElement* mKeyboardFocus; // Keyboard events are preemptively routed to this object + LLFocusableElement* mLastKeyboardFocus; // who last had focus + LLFocusableElement* mDefaultKeyboardFocus; BOOL mKeystrokesOnly; // Top View diff --git a/linden/indra/llui/llfunctorregistry.cpp b/linden/indra/llui/llfunctorregistry.cpp index 0c5b1655b..5f9644f25 100644 --- a/linden/indra/llui/llfunctorregistry.cpp +++ b/linden/indra/llui/llfunctorregistry.cpp @@ -31,6 +31,7 @@ * $/LicenseInfo$ **/ +#include "linden_common.h" #include "llfunctorregistry.h" // This is a default functor always resident in the system. diff --git a/linden/indra/llui/lliconctrl.cpp b/linden/indra/llui/lliconctrl.cpp index e73c8fe69..0df960e88 100644 --- a/linden/indra/llui/lliconctrl.cpp +++ b/linden/indra/llui/lliconctrl.cpp @@ -112,6 +112,12 @@ void LLIconCtrl::draw() LLUICtrl::draw(); } +// virtual +void LLIconCtrl::setAlpha(F32 alpha) +{ + mColor.setAlpha(alpha); +} + // virtual void LLIconCtrl::setValue(const LLSD& value ) { diff --git a/linden/indra/llui/lliconctrl.h b/linden/indra/llui/lliconctrl.h index 50778cf22..2506fb209 100644 --- a/linden/indra/llui/lliconctrl.h +++ b/linden/indra/llui/lliconctrl.h @@ -65,6 +65,8 @@ class LLIconCtrl virtual void setValue(const LLSD& value ); virtual LLSD getValue() const; + /*virtual*/ void setAlpha(F32 alpha); + void setColor(const LLColor4& color) { mColor = color; } virtual LLXMLNodePtr getXML(bool save_children = true) const; diff --git a/linden/indra/llui/llmenugl.cpp b/linden/indra/llui/llmenugl.cpp index 91bb58120..3c3d4ddb7 100644 --- a/linden/indra/llui/llmenugl.cpp +++ b/linden/indra/llui/llmenugl.cpp @@ -2194,9 +2194,16 @@ LLView* LLMenuGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa BOOL create_jump_keys = FALSE; node->getAttributeBOOL("create_jump_keys", create_jump_keys); + // If 'node' (the parent of the menu item 'child') has the attribute moonworld="true", + // then and only then hide all children that do NOT have that attribute. + bool parent_has_moonworld = node->hasMoonWorld(); LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { + if (!child->isMoonWorld(!parent_has_moonworld)) // Parent has attribute and child does not? + { + continue; // Skip it. + } menu->parseChildXML(child, parent, factory); } @@ -3235,9 +3242,17 @@ LLXMLNodePtr LLPieMenu::getXML(bool save_children) const void LLPieMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory) { + // If 'node' (the parent of the piemenu item 'child') has the attribute moonworld, + // then and only then hide all children that do NOT have that attribute (or have + // it set to false). + bool parent_has_moonworld = node->hasMoonWorld(); LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { + if (!child->isMoonWorld(!parent_has_moonworld)) // Parent has attribute and child does not? + { + continue; // Skip it. + } if (child->hasName(LL_PIE_MENU_TAG)) { // SUBMENU @@ -3782,6 +3797,9 @@ S32 LLPieMenu::pieItemIndexFromXY(S32 x, S32 y) void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down) { + // MoonWorld: Some pie menu's don't exist anymore. + if (!this) return; + S32 width = getRect().getWidth(); S32 height = getRect().getHeight(); @@ -3985,8 +4003,15 @@ LLView* LLMenuBarGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory } LLXMLNodePtr child; + // If the menubar 'node' (the parent of the menu item 'child') has the attribute moonworld="true", + // then and only then hide all children that do NOT have that attribute. + bool parent_has_moonworld = node->hasMoonWorld(); for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { + if (!child->isMoonWorld(!parent_has_moonworld)) // Parent has attribute and child does not? + { + continue; // Skip it. + } if (child->hasName("menu")) { LLMenuGL *menu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, factory); diff --git a/linden/indra/llui/llmenugl.h b/linden/indra/llui/llmenugl.h index 63f9d555d..8ab6fc472 100644 --- a/linden/indra/llui/llmenugl.h +++ b/linden/indra/llui/llmenugl.h @@ -434,7 +434,7 @@ class LLMenuGL // background colors static void setDefaultBackgroundColor( const LLColor4& color ) { sDefaultBackgroundColor = color; } - void setBackgroundColor( const LLColor4& color ) { mBackgroundColor = color; } + void setBackgroundColor( const LLColor4& color ) { if (this) { mBackgroundColor = color; } } const LLColor4& getBackgroundColor() const { return mBackgroundColor; } void setBackgroundVisible( BOOL b ) { mBgVisible = b; } void setCanTearOff(BOOL tear_off, LLHandle<LLFloater> parent_floater_handle = LLHandle<LLFloater>()); diff --git a/linden/indra/llui/llmultisliderctrl.cpp b/linden/indra/llui/llmultisliderctrl.cpp index b76c2f677..f9ec6d5ee 100644 --- a/linden/indra/llui/llmultisliderctrl.cpp +++ b/linden/indra/llui/llmultisliderctrl.cpp @@ -34,9 +34,6 @@ #include "llmultisliderctrl.h" -#include "audioengine.h" -#include "sound_ids.h" - #include "llmath.h" #include "llfontgl.h" #include "llgl.h" diff --git a/linden/indra/llui/llnotifications.cpp b/linden/indra/llui/llnotifications.cpp index 4d3ff462d..77f2ff778 100644 --- a/linden/indra/llui/llnotifications.cpp +++ b/linden/indra/llui/llnotifications.cpp @@ -40,7 +40,7 @@ #include <algorithm> #include <boost/regex.hpp> -#include "../newview/hippoGridManager.h" +#include "../newview/hippogridmanager.h" const std::string NOTIFICATION_PERSIST_VERSION = "0.93"; diff --git a/linden/indra/llui/llpanel.cpp b/linden/indra/llui/llpanel.cpp index 709342b70..7936715a4 100644 --- a/linden/indra/llui/llpanel.cpp +++ b/linden/indra/llui/llpanel.cpp @@ -203,6 +203,12 @@ void LLPanel::draw() LLView::draw(); } +/*virtual*/ +void LLPanel::setAlpha(F32 alpha) +{ + mBgColorOpaque.setAlpha(alpha); +} + void LLPanel::updateDefaultBtn() { // This method does not call LLView::draw() so callers will need @@ -213,8 +219,7 @@ void LLPanel::updateDefaultBtn() { if (gFocusMgr.childHasKeyboardFocus( this ) && mDefaultBtn->getEnabled()) { - LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus(); - LLButton* buttonp = dynamic_cast<LLButton*>(focus_ctrl); + LLButton* buttonp = dynamic_cast<LLButton*>(gFocusMgr.getKeyboardFocus()); BOOL focus_is_child_button = buttonp && buttonp->getCommitOnReturn(); // only enable default button when current focus is not a return-capturing button mDefaultBtn->setBorderEnabled(!focus_is_child_button); @@ -276,7 +281,7 @@ BOOL LLPanel::handleKeyHere( KEY key, MASK mask ) { BOOL handled = FALSE; - LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus(); + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); // handle user hitting ESC to defocus if (key == KEY_ESCAPE) @@ -800,6 +805,14 @@ void LLPanel::childSetColor(const std::string& id, const LLColor4& color) child->setColor(color); } } +void LLPanel::childSetAlpha(const std::string& id, F32 alpha) +{ + LLUICtrl* child = getChild<LLUICtrl>(id, true); + if (child) + { + child->setAlpha(alpha); + } +} LLCtrlSelectionInterface* LLPanel::childGetSelectionInterface(const std::string& id) const { @@ -1158,7 +1171,7 @@ void LLLayoutStack::draw() LLLocalClipRect clip(clip_rect); // only force drawing invisible children if visible amount is non-zero - drawChild(panelp, 0, 0, !clip_rect.isNull()); + drawChild(panelp, 0, 0, !clip_rect.isEmpty()); } } @@ -1251,8 +1264,16 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor layout_stackp->initFromXML(node, parent); LLXMLNodePtr child; + // If 'node' (the layoutstack) has the attribute moonworld="true", + // then and only then hide all children that do NOT have that attribute. + bool parent_has_moonworld = node->hasMoonWorld(); for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { + if (!child->isMoonWorld(!parent_has_moonworld)) // Parent has attribute and child does not? + { + continue; // Skip it. + } + S32 min_width = 0; S32 min_height = 0; BOOL auto_resize = TRUE; diff --git a/linden/indra/llui/llpanel.h b/linden/indra/llui/llpanel.h index 756d02ef7..378b3578f 100644 --- a/linden/indra/llui/llpanel.h +++ b/linden/indra/llui/llpanel.h @@ -82,6 +82,8 @@ class LLPanel : public LLUICtrl, public boost::signals::trackable // From LLFocusableElement /*virtual*/ void setFocus( BOOL b ); + virtual void setAlpha(F32 alpha); + // New virtuals virtual void refresh(); // called in setFocus() @@ -174,6 +176,7 @@ class LLPanel : public LLUICtrl, public boost::signals::trackable void childSetUserData(const std::string& id, void* userdata); void childSetColor(const std::string& id, const LLColor4& color); + void childSetAlpha(const std::string& id, F32 alpha); LLCtrlSelectionInterface* childGetSelectionInterface(const std::string& id) const; LLCtrlListInterface* childGetListInterface(const std::string& id) const; diff --git a/linden/indra/llui/llscrolllistctrl.cpp b/linden/indra/llui/llscrolllistctrl.cpp index 3c2293f54..1248a9a49 100644 --- a/linden/indra/llui/llscrolllistctrl.cpp +++ b/linden/indra/llui/llscrolllistctrl.cpp @@ -103,6 +103,10 @@ struct SortScrollListItem LLScrollListIcon::LLScrollListIcon(LLUIImagePtr icon, S32 width) : LLScrollListCell(width), mIcon(icon), + // <edit> + mCallback(NULL), + mUserData(NULL), + // </edit> mColor(LLColor4::white) { } @@ -145,6 +149,19 @@ void LLScrollListIcon::setValue(const LLSD& value) } } +// <edit> +void LLScrollListIcon::setClickCallback(BOOL (*callback)(void*), void* user_data) +{ + mCallback = callback; + mUserData = user_data; +} + +BOOL LLScrollListIcon::handleClick() +{ + if(mCallback) return mCallback(mUserData); + return FALSE; +} +// </edit> void LLScrollListIcon::setColor(const LLColor4& color) { @@ -588,6 +605,7 @@ LLScrollListCtrl::LLScrollListCtrl(const std::string& name, const LLRect& rect, mHighlightedColor( LLUI::sColorsGroup->getColor("ScrollHighlightedColor") ), mBorderThickness( 2 ), mOnDoubleClickCallback( NULL ), + mOnRightMouseDownCallback( NULL ), mOnMaximumSelectCallback( NULL ), mOnSortChangedCallback( NULL ), mHighlightedItem(-1), @@ -2065,6 +2083,27 @@ BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask) return TRUE; } +BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + //BOOL handled = FALSE; + BOOL handled = handleClick(x, y, mask); + + if (!handled) + { + // Offer the click to the children, even if we aren't enabled + // so the scroll bars will work. + if (NULL == LLView::childrenHandleRightMouseDown(x, y, mask)) + { + if( mCanSelect && mOnRightMouseDownCallback ) + { + mOnRightMouseDownCallback( x, y, mCallbackUserData ); + } + } + } + + return TRUE; +} + BOOL LLScrollListCtrl::handleClick(S32 x, S32 y, MASK mask) { // which row was clicked on? @@ -3614,6 +3653,22 @@ BOOL LLColumnHeader::handleDoubleClick(S32 x, S32 y, MASK mask) return TRUE; } +BOOL LLColumnHeader::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (canResize() && mResizeBar->getRect().pointInRect(x, y)) + { + // reshape column to max content width + LLRect column_rect = getRect(); + column_rect.mRight = column_rect.mLeft + mColumn->mMaxContentWidth; + userSetShape(column_rect); + } + else + { + onClick(this); + } + return TRUE; +} + void LLColumnHeader::setImage(const std::string &image_name) { if (mButton) diff --git a/linden/indra/llui/llscrolllistctrl.h b/linden/indra/llui/llscrolllistctrl.h index 516e4f1d6..4be7ff7e2 100644 --- a/linden/indra/llui/llscrolllistctrl.h +++ b/linden/indra/llui/llscrolllistctrl.h @@ -163,10 +163,18 @@ class LLScrollListIcon : public LLScrollListCell virtual void setColor(const LLColor4&); virtual BOOL isText()const { return FALSE; } virtual void setValue(const LLSD& value); + // <edit> + void setClickCallback(BOOL (*callback)(void*), void* user_data); + virtual BOOL handleClick(); + // </edit> private: LLUIImagePtr mIcon; LLColor4 mColor; + // <edit> + BOOL (*mCallback)(void*); + void* mUserData; + // </edit> }; /* @@ -233,6 +241,7 @@ class LLColumnHeader : public LLComboBox /*virtual*/ void draw(); /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ void showList(); /*virtual*/ LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding); @@ -423,6 +432,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, void highlightNthItem( S32 index ); void setDoubleClickCallback( void (*cb)(void*) ) { mOnDoubleClickCallback = cb; } + void setRightMouseDownCallback( void (*cb)(S32 x, S32 y, void*) ) { mOnRightMouseDownCallback = cb; } void setMaximumSelectCallback( void (*cb)(void*) ) { mOnMaximumSelectCallback = cb; } void setSortChangedCallback( void (*cb)(void*) ) { mOnSortChangedCallback = cb; } @@ -493,6 +503,9 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, virtual S32 getScrollPos() const; virtual void setScrollPos( S32 pos ); + // <edit> + S32 getPageLines() { return mPageLines; } + // </edit> S32 getSearchColumn(); void setSearchColumn(S32 column) { mSearchColumn = column; } S32 getColumnIndexFromOffset(S32 x); @@ -506,6 +519,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); @@ -649,6 +663,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, S32 mBorderThickness; void (*mOnDoubleClickCallback)(void* userdata); + void (*mOnRightMouseDownCallback)(S32 x, S32 y, void* userdata); void (*mOnMaximumSelectCallback)(void* userdata ); void (*mOnSortChangedCallback)(void* userdata); diff --git a/linden/indra/llui/llsliderctrl.cpp b/linden/indra/llui/llsliderctrl.cpp index 8a13ed42d..51d43fbb7 100644 --- a/linden/indra/llui/llsliderctrl.cpp +++ b/linden/indra/llui/llsliderctrl.cpp @@ -34,8 +34,6 @@ #include "llsliderctrl.h" -#include "audioengine.h" - #include "llmath.h" #include "llfontgl.h" #include "llgl.h" diff --git a/linden/indra/llui/llspinctrl.cpp b/linden/indra/llui/llspinctrl.cpp index 7eccaca09..e66b20ee1 100644 --- a/linden/indra/llui/llspinctrl.cpp +++ b/linden/indra/llui/llspinctrl.cpp @@ -45,7 +45,6 @@ #include "lltextbox.h" #include "llkeyboard.h" #include "llmath.h" -#include "audioengine.h" #include "llcontrol.h" #include "llfocusmgr.h" #include "llresmgr.h" diff --git a/linden/indra/llui/lltexteditor.cpp b/linden/indra/llui/lltexteditor.cpp index fdf8bcf94..004d06398 100644 --- a/linden/indra/llui/lltexteditor.cpp +++ b/linden/indra/llui/lltexteditor.cpp @@ -57,6 +57,7 @@ #include "llimagegl.h" #include "llwindow.h" #include "lltextparser.h" +#include "lldir.h" #include <queue> #include "llmenugl.h" @@ -4205,7 +4206,10 @@ void LLTextEditor::appendColoredText(const std::string &new_text, const std::string& font_name) { LLColor4 lcolor=color; - if (mParseHighlights) + // If LindenUserDir is empty then we didn't login yet. + // In that case we can't instantiate LLTextParser, which + // is initialized per user. + if (mParseHighlights && !gDirUtilp->getLindenUserDir(true).empty()) { LLTextParser* highlight = LLTextParser::getInstance(); highlight->parseFullLineHighlights(new_text, &lcolor); @@ -4285,7 +4289,10 @@ void LLTextEditor::appendHighlightedText(const std::string &new_text, S32 highlight_part, LLStyleSP stylep) { - if (mParseHighlights) + // If LindenUserDir is empty then we didn't login yet. + // In that case we can't instantiate LLTextParser, which + // is initialized per user. + if (mParseHighlights && !gDirUtilp->getLindenUserDir(true).empty()) { LLTextParser* highlight = LLTextParser::getInstance(); diff --git a/linden/indra/llui/lltextparser.cpp b/linden/indra/llui/lltextparser.cpp index 925b118f0..707dd0afd 100644 --- a/linden/indra/llui/lltextparser.cpp +++ b/linden/indra/llui/lltextparser.cpp @@ -1,6 +1,5 @@ /** - * @file lltexteditor.cpp - * @brief LLTextEditor base class + * @file lltextparser.cpp * * $LicenseInfo:firstyear=2001&license=viewergpl$ * @@ -32,6 +31,8 @@ #include "linden_common.h" +#include "lltextparser.h" + #include "llsd.h" #include "llsdserialize.h" #include "llerror.h" @@ -40,22 +41,12 @@ #include "message.h" #include "llmath.h" #include "v4color.h" -#include "audioengine.h" -#include "llwindow.h" #include "lldir.h" -#include "lltextparser.h" -//#include "lltexttospeech.h" - // Routines used for parsing text for TextParsers and html LLTextParser* LLTextParser::sInstance = NULL; -// -// Constants -// -const F32 SOUND_GAIN = 1.0f; - // // Member Functions // @@ -76,38 +67,7 @@ LLTextParser* LLTextParser::getInstance() return sInstance; } -void LLTextParser::triggerAlerts(LLUUID agent_id, LLVector3d position, std::string text, LLWindow* viewer_window) -{ -// bool spoken=FALSE; - for (S32 i=0;i<mHighlights.size();i++) - { - if (findPattern(text,mHighlights[i]) >= 0 ) - { - if(gAudiop) - { - if ((std::string)mHighlights[i]["sound_lluuid"] != LLUUID::null.asString()) - { - gAudiop->triggerSound(mHighlights[i]["sound_lluuid"].asUUID(), agent_id, SOUND_GAIN, LLAudioEngine::AUDIO_TYPE_UI, position); - } -/* - if (!spoken) - { - LLTextToSpeech* text_to_speech = NULL; - text_to_speech = LLTextToSpeech::getInstance(); - spoken = text_to_speech->speak((LLString)mHighlights[i]["voice"],text); - } - */ - } - if (mHighlights[i]["flash"]) - { - if (viewer_window && viewer_window->getMinimized()) - { - viewer_window->flashIcon(5.f); - } - } - } - } -} +// Moved triggerAlerts() to llfloaterchat.cpp to break llui/llaudio library dependency. S32 LLTextParser::findPattern(const std::string &text, LLSD highlight) { diff --git a/linden/indra/llui/lltextparser.h b/linden/indra/llui/lltextparser.h index d69e3a260..32343a2da 100644 --- a/linden/indra/llui/lltextparser.h +++ b/linden/indra/llui/lltextparser.h @@ -34,12 +34,8 @@ #ifndef LL_LLTEXTPARSER_H #define LL_LLTEXTPARSER_H -#include <vector> -#include "linden_common.h" +#include "llsd.h" -#include "lltextparser.h" - -class LLSD; class LLUUID; class LLVector3d; class LLColor4; @@ -59,7 +55,6 @@ class LLTextParser S32 findPattern(const std::string &text, LLSD highlight); LLSD parsePartialLineHighlights(const std::string &text,const LLColor4 &color,S32 part=WHOLE, S32 index=0); bool parseFullLineHighlights(const std::string &text, LLColor4 *color); - void triggerAlerts(LLUUID agent_id, LLVector3d position, std::string text, LLWindow* viewer_window); std::string getFileName(); LLSD loadFromDisk(); diff --git a/linden/indra/llui/llui.cpp b/linden/indra/llui/llui.cpp index 57ce13c9c..75a446782 100644 --- a/linden/indra/llui/llui.cpp +++ b/linden/indra/llui/llui.cpp @@ -38,7 +38,6 @@ #include <map> // Linden library includes -#include "audioengine.h" #include "v2math.h" #include "v4color.h" #include "llrender.h" diff --git a/linden/indra/llui/lluictrl.cpp b/linden/indra/llui/lluictrl.cpp index 9d97312ab..3f4ab5e45 100644 --- a/linden/indra/llui/lluictrl.cpp +++ b/linden/indra/llui/lluictrl.cpp @@ -39,54 +39,7 @@ static LLRegisterWidget<LLUICtrl> r("ui_ctrl"); -LLFocusableElement::LLFocusableElement() -: mFocusLostCallback(NULL), - mFocusReceivedCallback(NULL), - mFocusChangedCallback(NULL), - mFocusCallbackUserData(NULL) -{ -} - -//virtual -LLFocusableElement::~LLFocusableElement() -{ -} - -void LLFocusableElement::onFocusReceived() -{ - if( mFocusReceivedCallback ) - { - mFocusReceivedCallback( this, mFocusCallbackUserData ); - } - if( mFocusChangedCallback ) - { - mFocusChangedCallback( this, mFocusCallbackUserData ); - } -} - -void LLFocusableElement::onFocusLost() -{ - if( mFocusLostCallback ) - { - mFocusLostCallback( this, mFocusCallbackUserData ); - } - - if( mFocusChangedCallback ) - { - mFocusChangedCallback( this, mFocusCallbackUserData ); - } -} - -BOOL LLFocusableElement::hasFocus() const -{ - return FALSE; -} - -void LLFocusableElement::setFocus(BOOL b) -{ -} - - +// NOTE: the LLFocusableElement implementation has been moved to llfocusmgr.cpp, to mirror the header where the class is defined. LLUICtrl::LLUICtrl() : mCommitCallback(NULL), @@ -212,7 +165,7 @@ void LLUICtrl::onFocusReceived() // find first view in hierarchy above new focus that is a LLUICtrl LLView* viewp = getParent(); - LLUICtrl* last_focus = gFocusMgr.getLastKeyboardFocus(); + LLUICtrl* last_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getLastKeyboardFocus()); while (viewp && !viewp->isCtrl()) { @@ -590,6 +543,10 @@ void LLUICtrl::setDoubleClickCallback( void (*cb)(void*) ) // virtual void LLUICtrl::setColor(const LLColor4& color) { } +// virtual + +void LLUICtrl::setAlpha(F32 alpha) +{ } // virtual void LLUICtrl::setMinValue(LLSD min_value) diff --git a/linden/indra/llui/lluictrl.h b/linden/indra/llui/lluictrl.h index db41af847..be8e86336 100644 --- a/linden/indra/llui/lluictrl.h +++ b/linden/indra/llui/lluictrl.h @@ -39,31 +39,8 @@ #include "llsd.h" -class LLFocusableElement -{ - friend class LLFocusMgr; // allow access to focus change handlers -public: - LLFocusableElement(); - virtual ~LLFocusableElement(); - - virtual void setFocus( BOOL b ); - virtual BOOL hasFocus() const; - - void setFocusLostCallback(void (*cb)(LLFocusableElement* caller, void*), void* user_data = NULL) { mFocusLostCallback = cb; mFocusCallbackUserData = user_data; } - void setFocusReceivedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL) { mFocusReceivedCallback = cb; mFocusCallbackUserData = user_data; } - void setFocusChangedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL ) { mFocusChangedCallback = cb; mFocusCallbackUserData = user_data; } - -protected: - virtual void onFocusReceived(); - virtual void onFocusLost(); - void (*mFocusLostCallback)( LLFocusableElement* caller, void* userdata ); - void (*mFocusReceivedCallback)( LLFocusableElement* ctrl, void* userdata ); - void (*mFocusChangedCallback)( LLFocusableElement* ctrl, void* userdata ); - void* mFocusCallbackUserData; -}; - class LLUICtrl -: public LLView, public LLFocusableElement +: public LLView { public: typedef void (*LLUICtrlCallback)(LLUICtrl* ctrl, void* userdata); @@ -117,6 +94,7 @@ class LLUICtrl virtual void clear(); virtual void setDoubleClickCallback( void (*cb)(void*) ); virtual void setColor(const LLColor4& color); + virtual void setAlpha(F32 alpha); virtual void setMinValue(LLSD min_value); virtual void setMaxValue(LLSD max_value); diff --git a/linden/indra/llui/lluictrlfactory.cpp b/linden/indra/llui/lluictrlfactory.cpp index 5cfc3ee38..5e4232e0a 100644 --- a/linden/indra/llui/lluictrlfactory.cpp +++ b/linden/indra/llui/lluictrlfactory.cpp @@ -388,6 +388,12 @@ LLPieMenu *LLUICtrlFactory::buildPieMenu(const std::string &filename, LLView* pa return NULL; } + // MoonWorld: Don't show empty pie menu's. + if (!root->isMoonWorld(true)) // Has explicit attribute moonworld="false" ? + { + return NULL; + } + std::string name("menu"); root->getAttributeString("name", name); @@ -480,7 +486,14 @@ LLView *LLUICtrlFactory::createCtrlWidget(LLPanel *parent, LLXMLNodePtr node) } parent = mDummyPanel; } - LLView *ctrl = func(node, parent, this); + LLView *ctrl = NULL; + + // MoonWorld: Add widgets at normal, *unless* they have the attribute moonworld="false". + bool moonworld = true; + if (!node->getAttribute_bool("moonworld", moonworld) || moonworld) // Does not have the attribute, or it is set to "true"? + { + ctrl = func(node, parent, this); + } return ctrl; } diff --git a/linden/indra/llui/llview.cpp b/linden/indra/llui/llview.cpp index 8de376fb4..d4eda8f25 100644 --- a/linden/indra/llui/llview.cpp +++ b/linden/indra/llui/llview.cpp @@ -136,11 +136,6 @@ LLView::~LLView() { //llinfos << "Deleting view " << mName << ":" << (void*) this << llendl; // llassert(LLView::sIsDrawing == FALSE); - if( gFocusMgr.getKeyboardFocus() == this ) - { - llwarns << "View holding keyboard focus deleted: " << getName() << ". Keyboard focus removed." << llendl; - gFocusMgr.removeKeyboardFocusWithoutCallback( this ); - } if( hasMouseCapture() ) { @@ -1327,7 +1322,7 @@ void LLView::draw() LLRect screenRect; // draw focused control on top of everything else - LLView* focus_view = gFocusMgr.getKeyboardFocus(); + LLUICtrl* focus_view = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); if (focus_view && focus_view->getParent() != this) { focus_view = NULL; @@ -1547,7 +1542,7 @@ void LLView::updateBoundingRect() LLRect child_bounding_rect = childp->getBoundingRect(); - if (local_bounding_rect.isNull()) + if (local_bounding_rect.isEmpty()) { // start out with bounding rect equal to first visible child's bounding rect local_bounding_rect = child_bounding_rect; @@ -1555,7 +1550,7 @@ void LLView::updateBoundingRect() else { // accumulate non-null children rectangles - if (!child_bounding_rect.isNull()) + if (!child_bounding_rect.isEmpty()) { local_bounding_rect.unionWith(child_bounding_rect); } diff --git a/linden/indra/llui/llview.h b/linden/indra/llui/llview.h index 7e09dfa44..1c8ab3154 100644 --- a/linden/indra/llui/llview.h +++ b/linden/indra/llui/llview.h @@ -53,6 +53,7 @@ #include "stdenums.h" #include "lluistring.h" #include "llcursortypes.h" +#include "llfocusmgr.h" const U32 FOLLOWS_NONE = 0x00; const U32 FOLLOWS_LEFT = 0x01; @@ -207,7 +208,7 @@ class LLRegisterWidget } }; -class LLView : public LLMouseHandler, public LLMortician +class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElement { public: @@ -398,9 +399,11 @@ class LLView : public LLMouseHandler, public LLMortician virtual BOOL canSnapTo(const LLView* other_view); virtual void snappedTo(const LLView* snap_view); + + // inherited from LLFocusableElement + /* virtual */ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + /* virtual */ BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, @@ -421,8 +424,9 @@ class LLView : public LLMouseHandler, public LLMortician BOOL getSaveToXML() const { return mSaveToXML; } void setSaveToXML(BOOL b) { mSaveToXML = b; } - virtual void onFocusLost(); - virtual void onFocusReceived(); + // inherited from LLFocusableElement + /* virtual */ void onFocusLost(); + /* virtual */ void onFocusReceived(); typedef enum e_hit_test_type { diff --git a/linden/indra/llvfs/CMakeLists.txt b/linden/indra/llvfs/CMakeLists.txt index cc0297e3d..25b57e033 100644 --- a/linden/indra/llvfs/CMakeLists.txt +++ b/linden/indra/llvfs/CMakeLists.txt @@ -4,7 +4,6 @@ project(llvfs) include(00-Common) include(LLCommon) -include(UnixInstall) include_directories( ${LLCOMMON_INCLUDE_DIRS} diff --git a/linden/indra/llvfs/lldir.cpp b/linden/indra/llvfs/lldir.cpp index 2c3c5f76f..0c93cbbe6 100644 --- a/linden/indra/llvfs/lldir.cpp +++ b/linden/indra/llvfs/lldir.cpp @@ -43,6 +43,7 @@ #include "lldir.h" #include "llerror.h" #include "lluuid.h" +#include "lltimer.h" #if LL_WINDOWS #include "lldir_win32.h" @@ -192,8 +193,9 @@ const std::string &LLDir::getOSUserAppDir() const return mOSUserAppDir; } -const std::string &LLDir::getLindenUserDir() const +const std::string &LLDir::getLindenUserDir(bool empty_ok) const { + llassert(empty_ok || !mLindenUserDir.empty()); return mLindenUserDir; } @@ -294,6 +296,10 @@ const std::string LLDir::getSkinBaseDir() const return dir; } +const std::string &LLDir::getLLPluginDir() const +{ + return mLLPluginDir; +} std::string LLDir::getExpandedFilename(ELLPath location, const std::string& filename) const { @@ -465,6 +471,8 @@ std::string LLDir::getDirName(const std::string& filepath) const std::string LLDir::getExtension(const std::string& filepath) const { + if (filepath.empty()) + return std::string(); std::string basename = getBaseFileName(filepath, false); std::size_t offset = basename.find_last_of('.'); std::string exten = (offset == std::string::npos || offset == 0) ? "" : basename.substr(offset+1); diff --git a/linden/indra/llvfs/lldir.h b/linden/indra/llvfs/lldir.h index 21dcf5bd7..766f3518f 100644 --- a/linden/indra/llvfs/lldir.h +++ b/linden/indra/llvfs/lldir.h @@ -80,6 +80,10 @@ class LLDir virtual BOOL fileExists(const std::string &filename) const = 0; const std::string findFile(const std::string &filename, const std::string searchPath1 = "", const std::string searchPath2 = "", const std::string searchPath3 = "") const; + + virtual std::string getLLPluginLauncher() = 0; // full path and name for the plugin shell + virtual std::string getLLPluginFilename(std::string base_name) = 0; // full path and name to the plugin DSO for this base_name (i.e. 'FOO' -> '/bar/baz/libFOO.so') + const std::string &getExecutablePathAndName() const; // Full pathname of the executable const std::string &getAppName() const; // install directory under progams/ ie "SecondLife" const std::string &getExecutableDir() const; // Directory where the executable is located @@ -88,7 +92,7 @@ class LLDir const std::string &getAppRODataDir() const; // Location of read-only data files const std::string &getOSUserDir() const; // Location of the os-specific user dir const std::string &getOSUserAppDir() const; // Location of the os-specific user app dir - const std::string &getLindenUserDir() const; // Location of the Linden user dir. + const std::string &getLindenUserDir(bool empty_ok = false) const; // Location of the Linden user dir. const std::string &getChatLogsDir() const; // Location of the chat logs dir. const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir. const std::string &getTempDir() const; // Common temporary directory @@ -100,6 +104,7 @@ class LLDir const std::string &getUserSkinDir() const; // User-specified skin folder with user modifications. e.g. c:\documents and settings\username\application data\second life\skins\curskin const std::string &getDefaultSkinDir() const; // folder for default skin. e.g. c:\program files\second life\skins\default const std::string getSkinBaseDir() const; // folder that contains all installed skins (not user modifications). e.g. c:\program files\second life\skins + const std::string &getLLPluginDir() const; // Directory containing plugins and plugin shell // Expanded filename std::string getExpandedFilename(ELLPath location, const std::string &filename) const; @@ -156,6 +161,7 @@ class LLDir std::string mSkinDir; // Location for current skin info. std::string mDefaultSkinDir; // Location for default skin info. std::string mUserSkinDir; // Location for user-modified skin info. + std::string mLLPluginDir; // Location for plugins and plugin shell }; void dir_exists_or_crash(const std::string &dir_name); diff --git a/linden/indra/llvfs/lldir_linux.cpp b/linden/indra/llvfs/lldir_linux.cpp index 8ff8c5d1c..5f1eabb8d 100644 --- a/linden/indra/llvfs/lldir_linux.cpp +++ b/linden/indra/llvfs/lldir_linux.cpp @@ -94,14 +94,10 @@ LLDir_Linux::LLDir_Linux() mExecutablePathAndName = ""; mExecutableDir = tmp_str; mWorkingDir = tmp_str; -#ifdef APP_RO_DATA_DIR - mAppRODataDir = APP_RO_DATA_DIR; -#else mAppRODataDir = tmp_str; -#endif mOSUserDir = getCurrentUserHome(tmp_str); mOSUserAppDir = ""; - mLindenUserDir = tmp_str; + mLindenUserDir = ""; char path [32]; /* Flawfinder: ignore */ @@ -128,6 +124,33 @@ LLDir_Linux::LLDir_Linux() } } + mLLPluginDir = mExecutableDir + mDirDelimiter + "llplugin"; + +#ifdef APP_RO_DATA_DIR + const char* appRODataDir = APP_RO_DATA_DIR; + if(appRODataDir[0] == '/') + { + // We have a full path to the data directory. + mAppRODataDir = appRODataDir; + } + else if(appRODataDir[0] != '\0') + { + // We have a relative path to the data directory. Search + // for it in each potential install prefix containing the + // executable. + for(std::string prefix = getDirName(mExecutableDir); + !prefix.empty(); prefix = getDirName(prefix)) + { + std::string dir = prefix + "/" + appRODataDir; + if(fileExists(dir + "/app_settings")) + { + mAppRODataDir = dir; + break; + } + } + } +#endif + // *TODO: don't use /tmp, use $HOME/.secondlife/tmp or something. mTempDir = "/tmp"; } @@ -370,3 +393,15 @@ BOOL LLDir_Linux::fileExists(const std::string &filename) const } } + +/*virtual*/ std::string LLDir_Linux::getLLPluginLauncher() +{ + return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + + "SLPlugin"; +} + +/*virtual*/ std::string LLDir_Linux::getLLPluginFilename(std::string base_name) +{ + return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + "lib" + base_name + ".so"; +} diff --git a/linden/indra/llvfs/lldir_linux.h b/linden/indra/llvfs/lldir_linux.h index 20b408f8d..8e94fb1c9 100644 --- a/linden/indra/llvfs/lldir_linux.h +++ b/linden/indra/llvfs/lldir_linux.h @@ -52,6 +52,9 @@ class LLDir_Linux : public LLDir virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; + /*virtual*/ std::string getLLPluginLauncher(); + /*virtual*/ std::string getLLPluginFilename(std::string base_name); + private: DIR *mDirp; int mCurrentDirIndex; diff --git a/linden/indra/llvfs/lldir_mac.cpp b/linden/indra/llvfs/lldir_mac.cpp index b2d9787a9..6f0b0375f 100644 --- a/linden/indra/llvfs/lldir_mac.cpp +++ b/linden/indra/llvfs/lldir_mac.cpp @@ -190,6 +190,8 @@ LLDir_Mac::LLDir_Mac() } mWorkingDir = getCurPath(); + + mLLPluginDir = mAppRODataDir + mDirDelimiter + "llplugin"; CFRelease(executableURLRef); executableURLRef = NULL; @@ -388,4 +390,17 @@ BOOL LLDir_Mac::fileExists(const std::string &filename) const } +/*virtual*/ std::string LLDir_Mac::getLLPluginLauncher() +{ + return gDirUtilp->getAppRODataDir() + gDirUtilp->getDirDelimiter() + + "SLPlugin.app/Contents/MacOS/SLPlugin"; +} + +/*virtual*/ std::string LLDir_Mac::getLLPluginFilename(std::string base_name) +{ + return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + base_name + ".dylib"; +} + + #endif // LL_DARWIN diff --git a/linden/indra/llvfs/lldir_mac.h b/linden/indra/llvfs/lldir_mac.h index 28d48a0b6..8be5d03b2 100644 --- a/linden/indra/llvfs/lldir_mac.h +++ b/linden/indra/llvfs/lldir_mac.h @@ -52,6 +52,9 @@ class LLDir_Mac : public LLDir virtual void getRandomFileInDir(const std::string &dirname, const std::string &ask, std::string &fname); virtual BOOL fileExists(const std::string &filename) const; + /*virtual*/ std::string getLLPluginLauncher(); + /*virtual*/ std::string getLLPluginFilename(std::string base_name); + private: int mCurrentDirIndex; int mCurrentDirCount; diff --git a/linden/indra/llvfs/lldir_solaris.cpp b/linden/indra/llvfs/lldir_solaris.cpp index 9553d923a..5132455ff 100644 --- a/linden/indra/llvfs/lldir_solaris.cpp +++ b/linden/indra/llvfs/lldir_solaris.cpp @@ -100,7 +100,7 @@ LLDir_Solaris::LLDir_Solaris() mAppRODataDir = strdup(tmp_str); mOSUserDir = getCurrentUserHome(tmp_str); mOSUserAppDir = ""; - mLindenUserDir = tmp_str; + mLindenUserDir = ""; char path [LL_MAX_PATH]; /* Flawfinder: ignore */ @@ -161,6 +161,8 @@ LLDir_Solaris::LLDir_Solaris() } } + mLLPluginDir = mExecutableDir + mDirDelimiter + "llplugin"; + // *TODO: don't use /tmp, use $HOME/.secondlife/tmp or something. mTempDir = "/tmp"; } diff --git a/linden/indra/llvfs/lldir_win32.cpp b/linden/indra/llvfs/lldir_win32.cpp index 19b9bcc6e..9d4c5ecc8 100644 --- a/linden/indra/llvfs/lldir_win32.cpp +++ b/linden/indra/llvfs/lldir_win32.cpp @@ -143,6 +143,8 @@ LLDir_Win32::LLDir_Win32() llwarns << "Couldn't create LL_PATH_CACHE dir " << mDefaultCacheDir << llendl; } } + + mLLPluginDir = mExecutableDir + mDirDelimiter + "llplugin"; } LLDir_Win32::~LLDir_Win32() @@ -378,6 +380,19 @@ BOOL LLDir_Win32::fileExists(const std::string &filename) const } +/*virtual*/ std::string LLDir_Win32::getLLPluginLauncher() +{ + return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + + "SLPlugin.exe"; +} + +/*virtual*/ std::string LLDir_Win32::getLLPluginFilename(std::string base_name) +{ + return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + base_name + ".dll"; +} + + #if 0 // Utility function to get version number of a DLL diff --git a/linden/indra/llvfs/lldir_win32.h b/linden/indra/llvfs/lldir_win32.h index 8710ca50e..9ef4d300b 100644 --- a/linden/indra/llvfs/lldir_win32.h +++ b/linden/indra/llvfs/lldir_win32.h @@ -49,6 +49,9 @@ class LLDir_Win32 : public LLDir /*virtual*/ void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; + /*virtual*/ std::string getLLPluginLauncher(); + /*virtual*/ std::string getLLPluginFilename(std::string base_name); + private: BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname, BOOL wrap); diff --git a/linden/indra/llvfs/llpidlock.cpp b/linden/indra/llvfs/llpidlock.cpp index 93ac12030..cb6442816 100755 --- a/linden/indra/llvfs/llpidlock.cpp +++ b/linden/indra/llvfs/llpidlock.cpp @@ -39,6 +39,7 @@ #include "llsdserialize.h" #include "llnametable.h" #include "llframetimer.h" +#include "llapp.h" #if LL_WINDOWS //For windows platform. bool isProcessAlive(U32 pid) @@ -60,7 +61,7 @@ class LLPidLockFile public: LLPidLockFile( ) : mSaving(FALSE), mWaiting(FALSE), - mClean(TRUE), mPID(getpid()) + mClean(TRUE), mPID(LLApp::getPid()) { mLockName = gDirUtilp->getTempDir() + "/savelock"; } diff --git a/linden/indra/llvfs/llpidlock.h b/linden/indra/llvfs/llpidlock.h index 42aee4dc4..6103599b1 100755 --- a/linden/indra/llvfs/llpidlock.h +++ b/linden/indra/llvfs/llpidlock.h @@ -39,10 +39,10 @@ class LLFrameTimer; #if LL_WINDOWS //For windows platform. +# define WIN32_LEAN_AND_MEAN +# include <winsock2.h> #include <windows.h> -#define getpid GetCurrentProcessId - #else //Everyone Else #include <signal.h> diff --git a/linden/indra/llvfs/llvfile.cpp b/linden/indra/llvfs/llvfile.cpp index 6b1563bab..630975a05 100644 --- a/linden/indra/llvfs/llvfile.cpp +++ b/linden/indra/llvfs/llvfile.cpp @@ -38,6 +38,7 @@ #include "llthread.h" #include "llstat.h" #include "llvfs.h" +#include "llfasttimer.h" const S32 LLVFile::READ = 0x00000001; const S32 LLVFile::WRITE = 0x00000002; diff --git a/linden/indra/llvfs/llvfs.cpp b/linden/indra/llvfs/llvfs.cpp index 9bf5b5916..654dfa1ea 100644 --- a/linden/indra/llvfs/llvfs.cpp +++ b/linden/indra/llvfs/llvfs.cpp @@ -47,6 +47,7 @@ #include "llvfs.h" #include "llstl.h" +#include "lltimer.h" const S32 FILE_BLOCK_MASK = 0x000003FF; // 1024-byte blocks const S32 VFS_CLEANUP_SIZE = 5242880; // how much space we free up in a single stroke @@ -236,7 +237,7 @@ const S32 LLVFSFileBlock::SERIAL_SIZE = 34; LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash) : mRemoveAfterCrash(remove_after_crash) { - mDataMutex = new LLMutex(0); + mDataMutex = new LLMutex; S32 i; for (i = 0; i < VFSLOCK_COUNT; i++) diff --git a/linden/indra/llwindow/CMakeLists.txt b/linden/indra/llwindow/CMakeLists.txt index afce0c06c..98da751d3 100644 --- a/linden/indra/llwindow/CMakeLists.txt +++ b/linden/indra/llwindow/CMakeLists.txt @@ -19,7 +19,6 @@ include(LLRender) include(LLVFS) include(LLWindow) include(LLXML) -include(Mozlib) include(UI) include_directories( @@ -55,6 +54,21 @@ set(viewer_HEADER_FILES llmousehandler.h ) +# Libraries on which this library depends, needed for Linux builds +# Sort by high-level to low-level +if (LINUX) + set(llwindow_LINK_LIBRARIES + ${UI_LIBRARIES} # for GTK + ${SDL_LIBRARY} + fontconfig # For FCInit and other FC* functions. + ) +else (LINUX) + set(llwindow_LINK_LIBRARIES + ${UI_LIBRARIES} # for GTK + ${SDL_LIBRARY} + ) +endif (LINUX) + if (DARWIN) list(APPEND llwindow_SOURCE_FILES llkeyboardmacosx.cpp @@ -98,6 +112,9 @@ if (WINDOWS) lldxhardware.h llkeyboardwin32.h ) + list(APPEND llwindow_LINK_LIBRARIES + comdlg32 # Common Dialogs for ChooseColor + ) endif (WINDOWS) if (SOLARIS) @@ -134,6 +151,7 @@ if (SERVER AND NOT WINDOWS AND NOT DARWIN) ${server_SOURCE_FILES} ) endif (SERVER AND NOT WINDOWS AND NOT DARWIN) + # *TODO: This should probably have target_link_libraries if (llwindow_HEADER_FILES) list(APPEND llwindow_SOURCE_FILES ${llwindow_HEADER_FILES}) @@ -145,4 +163,6 @@ if (VIEWER) ${llwindow_SOURCE_FILES} ${viewer_SOURCE_FILES} ) + target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES}) endif (VIEWER) + diff --git a/linden/indra/llwindow/GL/glh_extensions.h b/linden/indra/llwindow/GL/glh_extensions.h index b936b5d30..5b149c992 100644 --- a/linden/indra/llwindow/GL/glh_extensions.h +++ b/linden/indra/llwindow/GL/glh_extensions.h @@ -17,6 +17,8 @@ #include <stdio.h> #ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include <winsock2.h> # include <windows.h> #endif diff --git a/linden/indra/llwindow/lldxhardware.cpp b/linden/indra/llwindow/lldxhardware.cpp index e0cb82d2b..d8058baf5 100644 --- a/linden/indra/llwindow/lldxhardware.cpp +++ b/linden/indra/llwindow/lldxhardware.cpp @@ -47,6 +47,7 @@ #include "llstring.h" #include "llstl.h" +#include "lltimer.h" void (*gWriteDebug)(const char* msg) = NULL; LLDXHardware gDXHardware; diff --git a/linden/indra/llwindow/llwindow.h b/linden/indra/llwindow/llwindow.h index 14759cccb..5e93ab32d 100644 --- a/linden/indra/llwindow/llwindow.h +++ b/linden/indra/llwindow/llwindow.h @@ -37,6 +37,7 @@ #include "llcoord.h" #include "llstring.h" #include "llcursortypes.h" +#include "llsd.h" class LLSplashScreen; @@ -195,7 +196,7 @@ class LLWindow // return a platform-specific window reference (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) virtual void *getPlatformWindow() = 0; -// return the platform-specific window reference we use to initialize llmozlib (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) +// return the platform-specific window reference we use to initialize llqtwebkitlib (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) virtual void *getMediaWindow(); // control platform's Language Text Input mechanisms. @@ -208,6 +209,9 @@ class LLWindow static std::vector<std::string> getDynamicFallbackFontList(); + // Provide native key event data + virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } + protected: LLWindow(BOOL fullscreen, U32 flags); virtual ~LLWindow() {} diff --git a/linden/indra/llwindow/llwindowmacosx-objc.h b/linden/indra/llwindow/llwindowmacosx-objc.h index 14c9c928f..9821698ec 100644 --- a/linden/indra/llwindow/llwindowmacosx-objc.h +++ b/linden/indra/llwindow/llwindowmacosx-objc.h @@ -5,7 +5,7 @@ * * $LicenseInfo:firstyear=2006&license=viewergpl$ * - * Copyright (c) 2006-2009, Linden Research, Inc. + * Copyright (c) 2006-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -49,4 +49,4 @@ CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY); OSErr releaseImageCursor(CursorRef ref); OSErr setImageCursor(CursorRef ref); BOOL decodeImageQuartz(std::string filename, LLImageRaw *raw_image); -BOOL decodeImageQuartz(const UInt8* data, int len, LLImageRaw *raw_image); +BOOL decodeImageQuartz(const UInt8* data, int len, LLImageRaw *raw_image, std::string ext); diff --git a/linden/indra/llwindow/llwindowmacosx-objc.mm b/linden/indra/llwindow/llwindowmacosx-objc.mm index abe8c5d9f..34ec4453b 100644 --- a/linden/indra/llwindow/llwindowmacosx-objc.mm +++ b/linden/indra/llwindow/llwindowmacosx-objc.mm @@ -5,7 +5,7 @@ * * $LicenseInfo:firstyear=2006&license=viewergpl$ * - * Copyright (c) 2006-2009, Linden Research, Inc. + * Copyright (c) 2006-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -43,12 +43,15 @@ */ #include "llwindowmacosx-objc.h" +#include "lldir.h" -BOOL decodeImageQuartz(const UInt8* data, int len, LLImageRaw *raw_image) +BOOL decodeImageQuartz(const UInt8* data, int len, LLImageRaw *raw_image, std::string ext) { CFDataRef theData = CFDataCreate(kCFAllocatorDefault, data, len); + CGImageSourceRef srcRef = CGImageSourceCreateWithData(theData, NULL); CGImageRef image_ref = CGImageSourceCreateImageAtIndex(srcRef, 0, NULL); + CFRelease(srcRef); size_t width = CGImageGetWidth(image_ref); size_t height = CGImageGetHeight(image_ref); @@ -58,7 +61,7 @@ BOOL decodeImageQuartz(const UInt8* data, int len, LLImageRaw *raw_image) UInt8* bitmap = (UInt8*)CFDataGetBytePtr(result); CGImageAlphaInfo format = CGImageGetAlphaInfo(image_ref); - if (format != kCGImageAlphaNone) + if (comps == 4) { vImage_Buffer vb; vb.data = bitmap; @@ -68,29 +71,13 @@ BOOL decodeImageQuartz(const UInt8* data, int len, LLImageRaw *raw_image) if (format & kCGImageAlphaPremultipliedFirst) { - // Ele: ARGB -> BGRA on Intel, need to first reorder the bytes, then unpremultiply as RGBA :) - llinfos << "Unpremultiplying BGRA8888" << llendl; - - for (int i=0; i<height; i++) - { - for (int j=0; j<bytes_per_row; j+=4) - { - unsigned char tmp[4]; - - tmp[0] = bitmap[j*height+3]; - tmp[1] = bitmap[j*height+2]; - tmp[2] = bitmap[j*height+1]; - tmp[3] = bitmap[j*height]; - - memcpy(&bitmap[j*height], &tmp, 4); - } - } - - vImageUnpremultiplyData_RGBA8888(&vb, &vb, 0); + // Ele: Skip unpremultiplication for PSD, PNG and TGA files + if (ext != std::string("psd") && ext != std::string("tga") && ext != std::string("png")) + vImageUnpremultiplyData_ARGB8888(&vb, &vb, 0); } else if (format & kCGImageAlphaPremultipliedLast) { - llinfos << "Unpremultiplying RGBA8888" << llendl; + // Ele: Photoshop Native Transparency needs unmultiplication vImageUnpremultiplyData_RGBA8888(&vb, &vb, 0); } } @@ -100,7 +87,6 @@ BOOL decodeImageQuartz(const UInt8* data, int len, LLImageRaw *raw_image) raw_image->verticalFlip(); CFRelease(theData); - CFRelease(srcRef); CGImageRelease(image_ref); CFRelease(result); @@ -112,7 +98,10 @@ BOOL decodeImageQuartz(std::string filename, LLImageRaw *raw_image) NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSURL *url = [[NSURL alloc] initFileURLWithPath:[NSString stringWithCString:filename.c_str()]]; NSData *data = [NSData dataWithContentsOfURL:url]; - BOOL result = decodeImageQuartz((UInt8*)[data bytes], [data length], raw_image); + + std::string ext = gDirUtilp->getExtension(filename); + + BOOL result = decodeImageQuartz((UInt8*)[data bytes], [data length], raw_image, ext); [pool release]; return result; } diff --git a/linden/indra/llwindow/llwindowmacosx.cpp b/linden/indra/llwindow/llwindowmacosx.cpp index 4dedc03bc..99daa4d46 100644 --- a/linden/indra/llwindow/llwindowmacosx.cpp +++ b/linden/indra/llwindow/llwindowmacosx.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -250,6 +250,7 @@ LLWindowMacOSX::LLWindowMacOSX(const std::string& title, const std::string& name mTSMScriptCode = 0; mTSMLangCode = 0; mPreeditor = NULL; + mRawKeyEvent = NULL; mFSAASamples = fsaa_samples; mForceRebuild = FALSE; @@ -1029,6 +1030,7 @@ void LLWindowMacOSX::hide() HideWindow(mWindow); } +//virtual void LLWindowMacOSX::minimize() { setMouseClipping(FALSE); @@ -1036,6 +1038,7 @@ void LLWindowMacOSX::minimize() CollapseWindow(mWindow, true); } +//virtual void LLWindowMacOSX::restore() { show(); @@ -1436,7 +1439,7 @@ static void fixOrigin(void) ::GetPortBounds(port, &portrect); if((portrect.left != 0) || (portrect.top != 0)) { - // Mozilla sometimes changes our port origin. Fuckers. + // Mozilla sometimes changes our port origin. ::SetOrigin(0,0); } } @@ -2128,10 +2131,11 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e { UInt32 modifiers = 0; + // First, process the raw event. { - EventRef rawEvent; - + EventRef rawEvent = NULL; + // Get the original event and extract the modifier keys, so we can ignore command-key events. if (GetEventParameter(event, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(rawEvent), NULL, &rawEvent) == noErr) { @@ -2140,6 +2144,9 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e // and call this function recursively to handle the raw key event. eventHandler (myHandler, rawEvent); + + // save the raw event until we're done processing the unicode input as well. + mRawKeyEvent = rawEvent; } } @@ -2167,11 +2174,8 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e } else { - MASK mask = 0; - if(modifiers & shiftKey) { mask |= MASK_SHIFT; } - if(modifiers & (cmdKey | controlKey)) { mask |= MASK_CONTROL; } - if(modifiers & optionKey) { mask |= MASK_ALT; } - + MASK mask = LLWindowMacOSX::modifiersToMask(modifiers); + llassert( actualType == typeUnicodeText ); // The result is a UTF16 buffer. Pass the characters in turn to handleUnicodeChar. @@ -2193,6 +2197,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e delete[] buffer; } + mRawKeyEvent = NULL; result = err; } break; @@ -2267,6 +2272,9 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); GetEventParameter (event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + // save the raw event so getNativeKeyData can use it. + mRawKeyEvent = event; + // printf("key event, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n", keyCode, charCode, (char)charCode, modifiers); // fflush(stdout); @@ -2362,6 +2370,8 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e result = eventNotHandledErr; break; } + + mRawKeyEvent = NULL; } break; @@ -3162,6 +3172,8 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url) OSStatus result = noErr; CFURLRef urlRef = NULL; + llinfos << "Opening URL " << escaped_url << llendl; + CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); if (stringRef) { @@ -3191,6 +3203,60 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url) } } +LLSD LLWindowMacOSX::getNativeKeyData() +{ + LLSD result = LLSD::emptyMap(); + + if(mRawKeyEvent) + { + char char_code = 0; + UInt32 key_code = 0; + UInt32 modifiers = 0; + UInt32 keyboard_type = 0; + + GetEventParameter (mRawKeyEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &char_code); + GetEventParameter (mRawKeyEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &key_code); + GetEventParameter (mRawKeyEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + GetEventParameter (mRawKeyEvent, kEventParamKeyboardType, typeUInt32, NULL, sizeof(UInt32), NULL, &keyboard_type); + + result["char_code"] = (S32)char_code; + result["key_code"] = (S32)key_code; + result["modifiers"] = (S32)modifiers; + result["keyboard_type"] = (S32)keyboard_type; + +#if 0 + // This causes trouble for control characters -- apparently character codes less than 32 (escape, control-A, etc) + // cause llsd serialization to create XML that the llsd deserializer won't parse! + std::string unicode; + OSStatus err = noErr; + EventParamType actualType = typeUTF8Text; + UInt32 actualSize = 0; + char *buffer = NULL; + + err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, 0, &actualSize, NULL); + if(err == noErr) + { + // allocate a buffer and get the actual data. + buffer = new char[actualSize]; + err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, actualSize, &actualSize, buffer); + if(err == noErr) + { + unicode.assign(buffer, actualSize); + } + delete[] buffer; + } + + result["unicode"] = unicode; +#endif + + } + + + lldebugs << "native key data is: " << result << llendl; + + return result; +} + void LLWindowMacOSX::ShellEx(const std::string& command) { OSStatus result = noErr; @@ -3217,7 +3283,7 @@ void LLWindowMacOSX::ShellEx(const std::string& command) } } -BOOL LLWindowMacOSX::dialog_color_picker ( F32 *r, F32 *g, F32 *b) +BOOL LLWindowMacOSX::dialog_color_picker( F32 *r, F32 *g, F32 *b) { BOOL retval = FALSE; OSErr error = noErr; @@ -3392,3 +3458,13 @@ std::vector<std::string> LLWindowMacOSX::getDynamicFallbackFontList() return std::vector<std::string>(); } +// static +MASK LLWindowMacOSX::modifiersToMask(SInt16 modifiers) +{ + MASK mask = 0; + if(modifiers & shiftKey) { mask |= MASK_SHIFT; } + if(modifiers & (cmdKey | controlKey)) { mask |= MASK_CONTROL; } + if(modifiers & optionKey) { mask |= MASK_ALT; } + return mask; +} + diff --git a/linden/indra/llwindow/llwindowmacosx.h b/linden/indra/llwindow/llwindowmacosx.h index 9e87e9fd3..8213b6913 100644 --- a/linden/indra/llwindow/llwindowmacosx.h +++ b/linden/indra/llwindow/llwindowmacosx.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -34,6 +34,7 @@ #define LL_LLWINDOWMACOSX_H #include "llwindow.h" +#include "lltimer.h" #include <Carbon/Carbon.h> #include <AGL/agl.h> @@ -55,6 +56,8 @@ class LLWindowMacOSX : public LLWindow /*virtual*/ BOOL getMinimized(); /*virtual*/ BOOL getMaximized(); /*virtual*/ BOOL maximize(); + /*virtual*/ void minimize(); + /*virtual*/ void restore(); /*virtual*/ BOOL getFullscreen(); /*virtual*/ BOOL getPosition(LLCoordScreen *position); /*virtual*/ BOOL getSize(LLCoordScreen *size); @@ -117,6 +120,10 @@ class LLWindowMacOSX : public LLWindow static std::vector<std::string> getDynamicFallbackFontList(); + // Provide native key event data + /*virtual*/ LLSD getNativeKeyData(); + + protected: LLWindowMacOSX( const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, @@ -139,9 +146,6 @@ class LLWindowMacOSX : public LLWindow // Restore the display resolution to its value before we ran the app. BOOL resetDisplayResolution(); - void minimize(); - void restore(); - BOOL shouldPostQuit() { return mPostQuit; } @@ -160,8 +164,8 @@ class LLWindowMacOSX : public LLWindow void adjustCursorDecouple(bool warpingMouse = false); void fixWindowSize(void); void stopDockTileBounce(); - - + static MASK modifiersToMask(SInt16 modifiers); + // // Platform specific variables // @@ -209,6 +213,7 @@ class LLWindowMacOSX : public LLWindow friend class LLWindowManager; static WindowRef sMediaWindow; + EventRef mRawKeyEvent; }; diff --git a/linden/indra/llwindow/llwindowsdl.cpp b/linden/indra/llwindow/llwindowsdl.cpp index 16a583aa6..f7d758790 100644 --- a/linden/indra/llwindow/llwindowsdl.cpp +++ b/linden/indra/llwindow/llwindowsdl.cpp @@ -42,6 +42,7 @@ #include "llstring.h" #include "lldir.h" #include "llfindlocale.h" +#include "lltimer.h" #include "indra_constants.h" @@ -250,6 +251,10 @@ LLWindowSDL::LLWindowSDL(const std::string& title, S32 x, S32 y, S32 width, #if LL_X11 mFlashing = FALSE; #endif // LL_X11 + + mKeyScanCode = 0; + mKeyVirtualKey = 0; + mKeyModifiers = KMOD_NONE; } static SDL_Surface *Load_BMP_Resource(const char *basename) @@ -1602,6 +1607,7 @@ void LLWindowSDL::processMiscNativeEvents() // the locale to protect it, as exotic/non-C locales // causes our code lots of general critical weirdness // and crashness. (SL-35450) + // Note: It is unknown if this is still needed now that we use webkit. static std::string saved_locale; saved_locale = ll_safe_string(setlocale(LC_ALL, NULL)); @@ -1935,11 +1941,6 @@ void LLWindowSDL::setCursor(ECursorType cursor) } } -ECursorType LLWindowSDL::getCursor() -{ - return mCurrentCursor; -} - void LLWindowSDL::initCursors() { int i; @@ -2227,7 +2228,40 @@ static void color_changed_callback(GtkWidget *widget, gtk_color_selection_get_current_color(colorsel, colorp); } -BOOL LLWindowSDL::dialog_color_picker ( F32 *r, F32 *g, F32 *b) + +/* + Make the raw keyboard data available - used to poke through to LLQtWebKit so + that Qt/Webkit has access to the virtual keycodes etc. that it needs +*/ +LLSD LLWindowSDL::getNativeKeyData() +{ + LLSD result = LLSD::emptyMap(); + + U32 modifiers = 0; // pretend-native modifiers... oh what a tangled web we weave! + + // we go through so many levels of device abstraction that I can't really guess + // what a plugin under GDK under Qt under SL under SDL under X11 considers + // a 'native' modifier mask. this has been sort of reverse-engineered... they *appear* + // to match GDK consts, but that may be co-incidence. + modifiers |= (mKeyModifiers & KMOD_LSHIFT) ? 0x0001 : 0; + modifiers |= (mKeyModifiers & KMOD_RSHIFT) ? 0x0001 : 0;// munge these into the same shift + modifiers |= (mKeyModifiers & KMOD_CAPS) ? 0x0002 : 0; + modifiers |= (mKeyModifiers & KMOD_LCTRL) ? 0x0004 : 0; + modifiers |= (mKeyModifiers & KMOD_RCTRL) ? 0x0004 : 0;// munge these into the same ctrl + modifiers |= (mKeyModifiers & KMOD_LALT) ? 0x0008 : 0;// untested + modifiers |= (mKeyModifiers & KMOD_RALT) ? 0x0008 : 0;// untested + // *todo: test ALTs - I don't have a case for testing these. Do you? + // *todo: NUM? - I don't care enough right now (and it's not a GDK modifier). + + result["scan_code"] = (S32)mKeyScanCode; + result["virtual_key"] = (S32)mKeyVirtualKey; + result["modifiers"] = (S32)modifiers; + + return result; +} + + +BOOL LLWindowSDL::dialog_color_picker( F32 *r, F32 *g, F32 *b) { BOOL rtn = FALSE; @@ -2396,7 +2430,7 @@ void *LLWindowSDL::getPlatformWindow() return rtnw; } #endif // LL_GTK && LL_LLMOZLIB_ENABLED - // Unixoid mozilla really needs GTK. + llassert(false); // Do we even GET here at all? Note that LL_LLMOZLIB_ENABLED is never defined! return NULL; } diff --git a/linden/indra/llwindow/llwindowsdl.h b/linden/indra/llwindow/llwindowsdl.h index 39a600718..e632dfebc 100644 --- a/linden/indra/llwindow/llwindowsdl.h +++ b/linden/indra/llwindow/llwindowsdl.h @@ -36,6 +36,7 @@ // Simple Directmedia Layer (http://libsdl.org/) implementation of LLWindow class #include "llwindow.h" +#include "lltimer.h" #include "SDL/SDL.h" #include "SDL/SDL_endian.h" @@ -77,7 +78,6 @@ class LLWindowSDL : public LLWindow /*virtual*/ void hideCursorUntilMouseMove(); /*virtual*/ BOOL isCursorHidden(); /*virtual*/ void setCursor(ECursorType cursor); - /*virtual*/ ECursorType getCursor(); /*virtual*/ void captureMouse(); /*virtual*/ void releaseMouse(); /*virtual*/ void setMouseClipping( BOOL b ); @@ -154,6 +154,8 @@ class LLWindowSDL : public LLWindow BOOL ignore_pixel_depth, U32 fsaa_samples); ~LLWindowSDL(); + /*virtual*/ LLSD getNativeKeyData(); + void initCursors(); void quitCursors(); BOOL isValid(); @@ -206,12 +208,17 @@ class LLWindowSDL : public LLWindow friend class LLWindowManager; -#if LL_X11 + private: +#if LL_X11 void x11_set_urgent(BOOL urgent); BOOL mFlashing; LLTimer mFlashTimer; #endif //LL_X11 + U32 mKeyScanCode; + U32 mKeyVirtualKey; + SDLMod mKeyModifiers; + }; diff --git a/linden/indra/llwindow/llwindowwin32.cpp b/linden/indra/llwindow/llwindowwin32.cpp index e47cab470..7bc9a3bf8 100644 --- a/linden/indra/llwindow/llwindowwin32.cpp +++ b/linden/indra/llwindow/llwindowwin32.cpp @@ -59,6 +59,8 @@ #include "llpreeditor.h" +#include "llfasttimer.h" + // culled from winuser.h #ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */ const S32 WM_MOUSEWHEEL = 0x020A; @@ -3052,6 +3054,19 @@ void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url ) */ } +/* + Make the raw keyboard data available - used to poke through to LLQtWebKit so + that Qt/Webkit has access to the virtual keycodes etc. that it needs +*/ +LLSD LLWindowWin32::getNativeKeyData() +{ + LLSD result = LLSD::emptyMap(); + + result["scan_code"] = (S32)mKeyScanCode; + result["virtual_key"] = (S32)mKeyVirtualKey; + + return result; +} BOOL LLWindowWin32::dialog_color_picker ( F32 *r, F32 *g, F32 *b ) { diff --git a/linden/indra/llwindow/llwindowwin32.h b/linden/indra/llwindow/llwindowwin32.h index cc95993b0..0e40115da 100644 --- a/linden/indra/llwindow/llwindowwin32.h +++ b/linden/indra/llwindow/llwindowwin32.h @@ -128,7 +128,7 @@ class LLWindowWin32 : public LLWindow HCURSOR loadColorCursor(LPCTSTR name); BOOL isValid(); void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); - + LLSD getNativeKeyData(); // Changes display resolution. Returns true if successful BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); @@ -208,6 +208,12 @@ class LLWindowWin32 : public LLWindow LLPreeditor *mPreeditor; + + + U32 mKeyCharCode; + U32 mKeyScanCode; + U32 mKeyVirtualKey; + friend class LLWindowManager; }; diff --git a/linden/indra/llxml/llcontrol.cpp b/linden/indra/llxml/llcontrol.cpp index 452167e10..004b75333 100644 --- a/linden/indra/llxml/llcontrol.cpp +++ b/linden/indra/llxml/llcontrol.cpp @@ -254,9 +254,9 @@ LLSD LLControlVariable::getSaveValue() const return mValues[0]; } -LLPointer<LLControlVariable> LLControlGroup::getControl(const std::string& name) +LLPointer<LLControlVariable> LLControlGroup::getControl(const std::string& name) const { - ctrl_name_table_t::iterator iter = mNameTable.find(name); + ctrl_name_table_t::const_iterator iter = mNameTable.find(name); return iter == mNameTable.end() ? LLPointer<LLControlVariable>() : iter->second; } @@ -452,7 +452,7 @@ std::string LLControlGroup::findString(const std::string& name) return LLStringUtil::null; } -std::string LLControlGroup::getString(const std::string& name) +std::string LLControlGroup::getString(const std::string& name) const { LLControlVariable* control = getControl(name); @@ -599,9 +599,9 @@ LLSD LLControlGroup::getLLSD(const std::string& name) return LLSD(); } -BOOL LLControlGroup::controlExists(const std::string& name) +BOOL LLControlGroup::controlExists(const std::string& name) const { - ctrl_name_table_t::iterator iter = mNameTable.find(name); + ctrl_name_table_t::const_iterator iter = mNameTable.find(name); return iter != mNameTable.end(); } diff --git a/linden/indra/llxml/llcontrol.h b/linden/indra/llxml/llcontrol.h index 316de5c20..f68c34389 100644 --- a/linden/indra/llxml/llcontrol.h +++ b/linden/indra/llxml/llcontrol.h @@ -160,7 +160,7 @@ class LLControlGroup : public LLControlGroupReader ~LLControlGroup(); void cleanup(); - LLPointer<LLControlVariable> getControl(const std::string& name); + LLPointer<LLControlVariable> getControl(const std::string& name) const; struct ApplyFunctor { @@ -185,7 +185,7 @@ class LLControlGroup : public LLControlGroupReader std::string findString(const std::string& name); - std::string getString(const std::string& name); + std::string getString(const std::string& name) const; LLWString getWString(const std::string& name); std::string getText(const std::string& name); LLVector3 getVector3(const std::string& name); @@ -220,7 +220,7 @@ class LLControlGroup : public LLControlGroupReader void setValue(const std::string& name, const LLSD& val); - BOOL controlExists(const std::string& name); + BOOL controlExists(const std::string& name) const; // Returns number of controls loaded, 0 if failed // If require_declaration is false, will auto-declare controls it finds diff --git a/linden/indra/llxml/llcontrolgroupreader.h b/linden/indra/llxml/llcontrolgroupreader.h index c4c04b98b..ef8ee18c9 100644 --- a/linden/indra/llxml/llcontrolgroupreader.h +++ b/linden/indra/llxml/llcontrolgroupreader.h @@ -46,7 +46,7 @@ class LLControlGroupReader LLControlGroupReader() {} virtual ~LLControlGroupReader() {} - virtual std::string getString(const std::string& name) = 0; + virtual std::string getString(const std::string& name) const = 0; //virtual LLWString getWString(const std::string& name) = 0; virtual std::string getText(const std::string& name) = 0; //virtual LLVector3 getVector3(const std::string& name) = 0; diff --git a/linden/indra/llxml/llxmlnode.cpp b/linden/indra/llxml/llxmlnode.cpp index 5bb501231..0972254a7 100644 --- a/linden/indra/llxml/llxmlnode.cpp +++ b/linden/indra/llxml/llxmlnode.cpp @@ -1241,6 +1241,25 @@ bool LLXMLNode::getAttribute_bool(const char* name, bool& value ) return retval; } +// Return true if this node has the attribute "moonworld". +bool LLXMLNode::hasMoonWorld() +{ + LLXMLNodePtr tmp; + return getAttribute("moonworld", tmp); +} + +// Return true if this node has the attribute "moonworld" and it's set to true, +// or when it doesn't have the attribute and default_value is true. +bool LLXMLNode::isMoonWorld(bool default_value) +{ + if (!hasMoonWorld()) + { + return default_value; + } + bool moonworld; + return getAttribute_bool("moonworld", moonworld) && moonworld; +} + BOOL LLXMLNode::getAttributeBOOL(const char* name, BOOL& value ) { LLXMLNodePtr node; diff --git a/linden/indra/llxml/llxmlnode.h b/linden/indra/llxml/llxmlnode.h index ab1a772ac..3242c0689 100644 --- a/linden/indra/llxml/llxmlnode.h +++ b/linden/indra/llxml/llxmlnode.h @@ -212,6 +212,8 @@ class LLXMLNode : public LLThreadSafeRefCount BOOL hasName(const char* name) const { return mName == gStringTable.checkStringEntry(name); } BOOL hasName(const std::string& name) const { return mName == gStringTable.checkStringEntry(name.c_str()); } const std::string& getID() const { return mID; } + bool hasMoonWorld(); + bool isMoonWorld(bool default_value); U32 getChildCount() const; // getChild returns a Null LLXMLNode (not a NULL pointer) if there is no such child. diff --git a/linden/indra/lscript/lscript_execute.h b/linden/indra/lscript/lscript_execute.h index 9a631c4c8..e2263fdbe 100644 --- a/linden/indra/lscript/lscript_execute.h +++ b/linden/indra/lscript/lscript_execute.h @@ -36,6 +36,7 @@ #include "lscript_byteconvert.h" #include "linked_lists.h" #include "lscript_library.h" +#include "lltimer.h" // Return values for run() methods const U32 NO_DELETE_FLAG = 0x0000; diff --git a/linden/indra/lscript/lscript_execute/llscriptresource.cpp b/linden/indra/lscript/lscript_execute/llscriptresource.cpp index 6c4776c2e..05ab8ebba 100644 --- a/linden/indra/lscript/lscript_execute/llscriptresource.cpp +++ b/linden/indra/lscript/lscript_execute/llscriptresource.cpp @@ -30,6 +30,7 @@ * $/LicenseInfo$ */ +#include "linden_common.h" #include "llscriptresource.h" #include "llerror.h" diff --git a/linden/indra/lscript/lscript_library/lscript_library.cpp b/linden/indra/lscript/lscript_library/lscript_library.cpp index 68daa50cc..cc56119ef 100644 --- a/linden/indra/lscript/lscript_library/lscript_library.cpp +++ b/linden/indra/lscript/lscript_library/lscript_library.cpp @@ -484,8 +484,9 @@ void LLScriptLibrary::init() // documented and therefore the description may be incomplete and require further attention. // OpenSimulator is written in C# and not CPP therefore some values for example "double = float" etc. are different. - // OSSL corrections and syntax additions added + set in same order as found in OSSL_stub.cs of OpenSim Source (February 19, 2010) - // based on OpenSimulator Ver. 0.6.9 DEV Git # af265e001d3bf043590e480cd6574a14193f6de0 - Rev 12239 + // OSSL corrections and syntax additions added + set in same order as found in OSSL_stub.cs of OpenSim Source (Updated PM October-21-2010 + // based on OpenSimulator Ver. 0.7.x DEV/Master Git # a7acb650d400a280a7b9edabd304376dff9c81af - a7acb65-r/14142 + // Updates by WhiteStar Magic addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osSetRegionWaterHeight", NULL, "f", "osSetRegionWaterHeight(float height)\nAdjusts Water Height on region.\n(OpenSim only.)")); addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osSetRegionSunSettings", NULL, "iif", "osSetRegionSunSettings(integer useEstateSun, integer sunFixed, float sunHour)\nChanges the Estate Sun Settings, then Triggers a Sun Update\n'sunFixed' TRUE (1) to keep the sun stationary, FALSE (0) to use global time\n'sunHour' The \"Sun Hour\" that is desired, 0...24, with 0 just after SunRise.\n(OpenSim only.)")); @@ -494,8 +495,11 @@ void LLScriptLibrary::init() addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osSunGetParam","f", "s", "float osSunGetParam(string param)\nReturns current float values for param\nwhere param = day_length, year_length, day_night_offset, update_interval.\n(OpenSim only.)")); addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osSunSetParam", "sf", NULL, "osSunSetParam(string param, float value)\nSet's Sun Param for SunSet,\nosSunSetParam(day_length, 24.0)\nwhere param = day_length, year_length, day_night_offset, update_interval.\n(OpenSim only.)")); addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osWindActiveModelPluginName", "s", NULL, "string osWindActiveModelPluginName()\nReturns the Current Working Wind Module Installed\nThese are SimpleRandomWind or ConfigurableWind, optionally others.\n(OpenSim only.)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osWindParamSet", NULL, "ssf", "osWindParamSet(string plugin, string param, float value)Send Param to Specified Wind Plugin with new value.\n(OpenSim only.)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osWindParamGet", "f", "ss", "float osWindParamGet(string plugin, string param)\n Returns Current param from specified Wind Plugin Module.\n(OpenSim only.)")); + addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osParcelJoin", NULL, "vv", "osParcelJoin(vector pos1, vector pos2))\nJoins Parcels @ X,Y coordinates.\n(OpenSim only.)")); + addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osParcelSubdivide", NULL, "vv", "osParcelSubdivide(vector pos1, vector pos2))\nSubdivides Parcels @ X,Y coordinates.\n(OpenSim only.)")); + addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osParcelSetDetails", NULL, "vv", "osParcelSetDetails(vector pos, list rules))\nSet Parcel details.\n(OpenSim only.)")); + // addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osWindParamSet", NULL, "ssf", "osWindParamSet(string plugin, string param, float value)Send Param to Specified Wind Plugin with new value.\n(OpenSim only.)")); + // addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osWindParamGet", "f", "ss", "float osWindParamGet(string plugin, string param)\n Returns Current param from specified Wind Plugin Module.\n(OpenSim only.)")); addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osList2Double", "f", "si", "double osList2Double(list src, int index)\nReturns Double (float) Value from src at index.\n(OpenSim only.)")); addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osSetDynamicTextureURL", NULL, "ssssi", "osSetDynamicTextureURL(string dynamicID, string contentType, string url, string extraParams, int timer )\n(OpenSim only.)")); addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osSetDynamicTextureData", NULL, "ssssi", "osSetDynamicTextureData(string dynamicID, string contentType, string data, string extraParams, int timer)\nWrites text and vector graphics onto a prim face.\n(OpenSim only.)")); @@ -564,7 +568,9 @@ void LLScriptLibrary::init() addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osSetSpeed", NULL, "kf", "osSetSpeed(key AVATAR, float SpeedModifier)\nMultiplies the normal running, walking, and flying speed of the specified avatar.\n(OpenSim only.)")); addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osCauseDamage", NULL, "kf", "osCauseDamage(key AVATAR, float damage)\nCauses damage to specified AVATAR (UUID).\n(OpenSim only.)")); addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osCauseHealing", NULL, "kf", "osCauseHealing(key AVATAR, float healing)\nCauses Healing to specified AVATAR (UUID).\n(OpenSim only.)")); - + addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osGetPrimitiveParams", "l", "kl", "List osGetPrimitiveParams(key prim, list rules)\nGets primitive Params.\n(OpenSim only.)")); + addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osSetPrimitiveParams", NULL, "kl", "osSetPrimitiveParams(key prim, list rules)\nSets primitive Params.\n(OpenSim only.)")); + addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "osSetProjectionParams", NULL, "kikfff", "osSetProjectionParams(key prim. bool projection, key texture, float fov, float focus, float amb)\nSet Projection Paramaters (bool = true / false)\n(OpenSim only.)")); // LightShare functions addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "cmSetWindlightScene", "i", "l", "integer cmSetWindlightScene(list rules)\nSet the current WindLight scene. Restricted to estate managers and owners only.")); diff --git a/linden/indra/media_plugins/CMakeLists.txt b/linden/indra/media_plugins/CMakeLists.txt new file mode 100755 index 000000000..a4c6b1845 --- /dev/null +++ b/linden/indra/media_plugins/CMakeLists.txt @@ -0,0 +1,15 @@ +# -*- cmake -*- + +add_subdirectory(base) + +add_subdirectory(webkit) + +if (LINUX) + add_subdirectory(gstreamer010) +endif (LINUX) + +if (WINDOWS OR DARWIN) + add_subdirectory(quicktime) +endif (WINDOWS OR DARWIN) + +add_subdirectory(example) diff --git a/linden/indra/media_plugins/base/CMakeLists.txt b/linden/indra/media_plugins/base/CMakeLists.txt new file mode 100644 index 000000000..8d620433a --- /dev/null +++ b/linden/indra/media_plugins/base/CMakeLists.txt @@ -0,0 +1,49 @@ +# -*- cmake -*- + +project(media_plugin_base) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(FindOpenGL) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} +) + + +### media_plugin_base + +if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + if(WINDOWS) + add_definitions(/FIXED:NO) + else(WINDOWS) # not windows therefore gcc LINUX and DARWIN + add_definitions(-fPIC) + endif(WINDOWS) +endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + +set(media_plugin_base_SOURCE_FILES + media_plugin_base.cpp +) + +set(media_plugin_base_HEADER_FILES + CMakeLists.txt + + media_plugin_base.h +) + +add_library(media_plugin_base + ${media_plugin_base_SOURCE_FILES} +) + diff --git a/linden/indra/media_plugins/base/media_plugin_base.cpp b/linden/indra/media_plugins/base/media_plugin_base.cpp new file mode 100755 index 000000000..47acdfd28 --- /dev/null +++ b/linden/indra/media_plugins/base/media_plugin_base.cpp @@ -0,0 +1,213 @@ +/** + * @file media_plugin_base.cpp + * @brief Media plugin base class for LLMedia API plugin system + * + * All plugins should be a subclass of MediaPluginBase. + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" +#include "media_plugin_base.h" + + +// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint +//////////////////////////////////////////////////////////////////////////////// +/// Media plugin constructor. +/// +/// @param[in] host_send_func Function for sending messages from plugin to plugin loader shell +/// @param[in] host_user_data Message data for messages from plugin to plugin loader shell + +MediaPluginBase::MediaPluginBase( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) +{ + mHostSendFunction = host_send_func; + mHostUserData = host_user_data; + mDeleteMe = false; + mPixels = 0; + mWidth = 0; + mHeight = 0; + mTextureWidth = 0; + mTextureHeight = 0; + mDepth = 0; + mStatus = STATUS_NONE; +} + +/** + * Converts current media status enum value into string (STATUS_LOADING into "loading", etc.) + * + * @return Media status string ("loading", "playing", "paused", etc) + * + */ +std::string MediaPluginBase::statusString() +{ + std::string result; + + switch(mStatus) + { + case STATUS_LOADING: result = "loading"; break; + case STATUS_LOADED: result = "loaded"; break; + case STATUS_ERROR: result = "error"; break; + case STATUS_PLAYING: result = "playing"; break; + case STATUS_PAUSED: result = "paused"; break; + case STATUS_DONE: result = "done"; break; + default: + // keep the empty string + break; + } + + return result; +} + +/** + * Set media status. + * + * @param[in] status Media status (STATUS_LOADING, STATUS_PLAYING, STATUS_PAUSED, etc) + * + */ +void MediaPluginBase::setStatus(EStatus status) +{ + if(mStatus != status) + { + mStatus = status; + sendStatus(); + } +} + + +/** + * Receive message from plugin loader shell. + * + * @param[in] message_string Message string + * @param[in] user_data Message data + * + */ +void MediaPluginBase::staticReceiveMessage(const char *message_string, void **user_data) +{ + MediaPluginBase *self = (MediaPluginBase*)*user_data; + + if(self != NULL) + { + self->receiveMessage(message_string); + + // If the plugin has processed the delete message, delete it. + if(self->mDeleteMe) + { + delete self; + *user_data = NULL; + } + } +} + +/** + * Send message to plugin loader shell. + * + * @param[in] message Message data being sent to plugin loader shell + * + */ +void MediaPluginBase::sendMessage(const LLPluginMessage &message) +{ + std::string output = message.generate(); + mHostSendFunction(output.c_str(), &mHostUserData); +} + +/** + * Notifies plugin loader shell that part of display area needs to be redrawn. + * + * @param[in] left Left X coordinate of area to redraw (0,0 is at top left corner) + * @param[in] top Top Y coordinate of area to redraw (0,0 is at top left corner) + * @param[in] right Right X-coordinate of area to redraw (0,0 is at top left corner) + * @param[in] bottom Bottom Y-coordinate of area to redraw (0,0 is at top left corner) + * + */ +void MediaPluginBase::setDirty(int left, int top, int right, int bottom) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated"); + + message.setValueS32("left", left); + message.setValueS32("top", top); + message.setValueS32("right", right); + message.setValueS32("bottom", bottom); + + sendMessage(message); +} + +/** + * Sends "media_status" message to plugin loader shell ("loading", "playing", "paused", etc.) + * + */ +void MediaPluginBase::sendStatus() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "media_status"); + + message.setValue("status", statusString()); + + sendMessage(message); +} + + +#if LL_WINDOWS +# define LLSYMEXPORT __declspec(dllexport) +#elif LL_LINUX +# define LLSYMEXPORT __attribute__ ((visibility("default"))) +#else +# define LLSYMEXPORT /**/ +#endif + +extern "C" +{ + LLSYMEXPORT int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); +} + +/** + * Plugin initialization and entry point. Establishes communication channel for messages between plugin and plugin loader shell. TODO:DOC - Please check! + * + * @param[in] host_send_func Function for sending messages from plugin to plugin loader shell + * @param[in] host_user_data Message data for messages from plugin to plugin loader shell + * @param[out] plugin_send_func Function for plugin to receive messages from plugin loader shell + * @param[out] plugin_user_data Pointer to plugin instance + * + * @return int, where 0=success + * + */ +LLSYMEXPORT int +LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + return init_media_plugin(host_send_func, host_user_data, plugin_send_func, plugin_user_data); +} + +#ifdef WIN32 +int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* params ) +{ + return 1; +} +#endif diff --git a/linden/indra/media_plugins/base/media_plugin_base.exp b/linden/indra/media_plugins/base/media_plugin_base.exp new file mode 100755 index 000000000..d8c7bb712 --- /dev/null +++ b/linden/indra/media_plugins/base/media_plugin_base.exp @@ -0,0 +1,2 @@ +_LLPluginInitEntryPoint + diff --git a/linden/indra/media_plugins/base/media_plugin_base.h b/linden/indra/media_plugins/base/media_plugin_base.h new file mode 100755 index 000000000..efb0629a5 --- /dev/null +++ b/linden/indra/media_plugins/base/media_plugin_base.h @@ -0,0 +1,136 @@ +/** + * @file media_plugin_base.h + * @brief Media plugin base class for LLMedia API plugin system + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" + + +class MediaPluginBase +{ +public: + MediaPluginBase(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + /** Media plugin destructor. */ + virtual ~MediaPluginBase() {} + + /** Handle received message from plugin loader shell. */ + virtual void receiveMessage(const char *message_string) = 0; + + static void staticReceiveMessage(const char *message_string, void **user_data); + +protected: + + /** Plugin status. */ + typedef enum + { + STATUS_NONE, + STATUS_LOADING, + STATUS_LOADED, + STATUS_ERROR, + STATUS_PLAYING, + STATUS_PAUSED, + STATUS_DONE + } EStatus; + + /** Plugin shared memory. */ + class SharedSegmentInfo + { + public: + /** Shared memory address. */ + void *mAddress; + /** Shared memory size. */ + size_t mSize; + }; + + void sendMessage(const LLPluginMessage &message); + void sendStatus(); + std::string statusString(); + void setStatus(EStatus status); + + /// Note: The quicktime plugin overrides this to add current time and duration to the message. + virtual void setDirty(int left, int top, int right, int bottom); + + /** Map of shared memory names to shared memory. */ + typedef std::map<std::string, SharedSegmentInfo> SharedSegmentMap; + + + /** Function to send message from plugin to plugin loader shell. */ + LLPluginInstance::sendMessageFunction mHostSendFunction; + /** Message data being sent to plugin loader shell by mHostSendFunction. */ + void *mHostUserData; + /** Flag to delete plugin instance (self). */ + bool mDeleteMe; + /** Pixel array to display. TODO:DOC are pixels always 24-bit RGB format, aligned on 32-bit boundary? Also: calling this a pixel array may be misleading since 1 pixel > 1 char. */ + unsigned char* mPixels; + /** TODO:DOC what's this for -- does a texture have its own piece of shared memory? updated on size_change_request, cleared on shm_remove */ + std::string mTextureSegmentName; + /** Width of plugin display in pixels. */ + int mWidth; + /** Height of plugin display in pixels. */ + int mHeight; + /** Width of plugin texture. */ + int mTextureWidth; + /** Height of plugin texture. */ + int mTextureHeight; + /** Pixel depth (pixel size in bytes). */ + int mDepth; + /** Current status of plugin. */ + EStatus mStatus; + /** Map of shared memory segments. */ + SharedSegmentMap mSharedSegments; + +}; + +/** The plugin <b>must</b> define this function to create its instance. + * It should look something like this: + * @code + * { + * MediaPluginFoo *self = new MediaPluginFoo(host_send_func, host_user_data); + * *plugin_send_func = MediaPluginFoo::staticReceiveMessage; + * *plugin_user_data = (void*)self; + * + * return 0; + * } + * @endcode + */ +int init_media_plugin( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data, + LLPluginInstance::sendMessageFunction *plugin_send_func, + void **plugin_user_data); + + diff --git a/linden/indra/media_plugins/example/CMakeLists.txt b/linden/indra/media_plugins/example/CMakeLists.txt new file mode 100644 index 000000000..7822300ba --- /dev/null +++ b/linden/indra/media_plugins/example/CMakeLists.txt @@ -0,0 +1,82 @@ +# -*- cmake -*- + +project(media_plugin_example) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(MediaPluginBase) +include(FindOpenGL) + +#include(ExamplePlugin) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} +) + + +### media_plugin_example + +if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + if(WINDOWS) + add_definitions(/FIXED:NO) + else(WINDOWS) # not windows therefore gcc LINUX and DARWIN + add_definitions(-fPIC) + endif(WINDOWS) +endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4) + +set(media_plugin_example_SOURCE_FILES + media_plugin_example.cpp + ) + +add_library(media_plugin_example + SHARED + ${media_plugin_example_SOURCE_FILES} +) + +target_link_libraries(media_plugin_example + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${EXAMPLE_PLUGIN_LIBRARIES} + ${PLUGIN_API_WINDOWS_LIBRARIES} +) + +add_dependencies(media_plugin_example + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + +if (WINDOWS) + set_target_properties( + media_plugin_example + PROPERTIES + LINK_FLAGS "/MANIFEST:NO" + ) +endif (WINDOWS) + +if (DARWIN) + # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name + set_target_properties( + media_plugin_example + PROPERTIES + PREFIX "" + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" + ) + +endif (DARWIN) diff --git a/linden/indra/media_plugins/example/media_plugin_example.cpp b/linden/indra/media_plugins/example/media_plugin_example.cpp new file mode 100755 index 000000000..1eabe6c85 --- /dev/null +++ b/linden/indra/media_plugins/example/media_plugin_example.cpp @@ -0,0 +1,494 @@ +/** + * @file media_plugin_example.cpp + * @brief Example plugin for LLMedia API plugin system + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" + +#include "llgl.h" +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#include <time.h> + +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginExample : + public MediaPluginBase +{ + public: + MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ); + ~MediaPluginExample(); + + /*virtual*/ void receiveMessage( const char* message_string ); + + private: + bool init(); + void update( F64 milliseconds ); + void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ); + bool mFirstTime; + + time_t mLastUpdateTime; + enum Constants { ENumObjects = 10 }; + unsigned char* mBackgroundPixels; + int mColorR[ ENumObjects ]; + int mColorG[ ENumObjects ]; + int mColorB[ ENumObjects ]; + int mXpos[ ENumObjects ]; + int mYpos[ ENumObjects ]; + int mXInc[ ENumObjects ]; + int mYInc[ ENumObjects ]; + int mBlockSize[ ENumObjects ]; + bool mMouseButtonDown; + bool mStopAction; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +MediaPluginExample::MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ) : + MediaPluginBase( host_send_func, host_user_data ) +{ + mFirstTime = true; + mWidth = 0; + mHeight = 0; + mDepth = 4; + mPixels = 0; + mMouseButtonDown = false; + mStopAction = false; + mLastUpdateTime = 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// +MediaPluginExample::~MediaPluginExample() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginExample::receiveMessage( const char* message_string ) +{ + LLPluginMessage message_in; + + if ( message_in.parse( message_string ) >= 0 ) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + + if ( message_class == LLPLUGIN_MESSAGE_CLASS_BASE ) + { + if ( message_name == "init" ) + { + LLPluginMessage message( "base", "init_response" ); + LLSD versions = LLSD::emptyMap(); + versions[ LLPLUGIN_MESSAGE_CLASS_BASE ] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[ LLPLUGIN_MESSAGE_CLASS_MEDIA ] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[ LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER ] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; + message.setValueLLSD( "versions", versions ); + + std::string plugin_version = "Example media plugin, Example Version 1.0.0.0"; + message.setValue( "plugin_version", plugin_version ); + sendMessage( message ); + } + else + if ( message_name == "idle" ) + { + // no response is necessary here. + F64 time = message_in.getValueReal( "time" ); + + // Convert time to milliseconds for update() + update( time ); + } + else + if ( message_name == "cleanup" ) + { + // clean up here + } + else + if ( message_name == "shm_added" ) + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer( "address" ); + info.mSize = ( size_t )message_in.getValueS32( "size" ); + std::string name = message_in.getValue( "name" ); + + mSharedSegments.insert( SharedSegmentMap::value_type( name, info ) ); + + } + else + if ( message_name == "shm_remove" ) + { + std::string name = message_in.getValue( "name" ); + + SharedSegmentMap::iterator iter = mSharedSegments.find( name ); + if( iter != mSharedSegments.end() ) + { + if ( mPixels == iter->second.mAddress ) + { + // This is the currently active pixel buffer. + // Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + }; + mSharedSegments.erase( iter ); + } + else + { + //std::cerr << "MediaPluginExample::receiveMessage: unknown shared memory region!" << std::endl; + }; + + // Send the response so it can be cleaned up. + LLPluginMessage message( "base", "shm_remove_response" ); + message.setValue( "name", name ); + sendMessage( message ); + } + else + { + //std::cerr << "MediaPluginExample::receiveMessage: unknown base message: " << message_name << std::endl; + }; + } + else + if ( message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA ) + { + if ( message_name == "init" ) + { + // Plugin gets to decide the texture parameters to use. + LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params" ); + message.setValueS32( "default_width", mWidth ); + message.setValueS32( "default_height", mHeight ); + message.setValueS32( "depth", mDepth ); + message.setValueU32( "internalformat", GL_RGBA ); + message.setValueU32( "format", GL_RGBA ); + message.setValueU32( "type", GL_UNSIGNED_BYTE ); + message.setValueBoolean( "coords_opengl", false ); + sendMessage( message ); + } + else if ( message_name == "size_change" ) + { + std::string name = message_in.getValue( "name" ); + S32 width = message_in.getValueS32( "width" ); + S32 height = message_in.getValueS32( "height" ); + S32 texture_width = message_in.getValueS32( "texture_width" ); + S32 texture_height = message_in.getValueS32( "texture_height" ); + + if ( ! name.empty() ) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find( name ); + if ( iter != mSharedSegments.end() ) + { + mPixels = ( unsigned char* )iter->second.mAddress; + mWidth = width; + mHeight = height; + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + init(); + }; + }; + + LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response" ); + message.setValue( "name", name ); + message.setValueS32( "width", width ); + message.setValueS32( "height", height ); + message.setValueS32( "texture_width", texture_width ); + message.setValueS32( "texture_height", texture_height ); + sendMessage( message ); + } + else + if ( message_name == "load_uri" ) + { + std::string uri = message_in.getValue( "uri" ); + if ( ! uri.empty() ) + { + }; + } + else + if ( message_name == "mouse_event" ) + { + std::string event = message_in.getValue( "event" ); + S32 button = message_in.getValueS32( "button" ); + + // left mouse button + if ( button == 0 ) + { + int mouse_x = message_in.getValueS32( "x" ); + int mouse_y = message_in.getValueS32( "y" ); + std::string modifiers = message_in.getValue( "modifiers" ); + + if ( event == "move" ) + { + if ( mMouseButtonDown ) + write_pixel( mouse_x, mouse_y, rand() % 0x80 + 0x80, rand() % 0x80 + 0x80, rand() % 0x80 + 0x80 ); + } + else + if ( event == "down" ) + { + mMouseButtonDown = true; + } + else + if ( event == "up" ) + { + mMouseButtonDown = false; + } + else + if ( event == "double_click" ) + { + }; + }; + } + else + if ( message_name == "key_event" ) + { + std::string event = message_in.getValue( "event" ); + S32 key = message_in.getValueS32( "key" ); + std::string modifiers = message_in.getValue( "modifiers" ); + + if ( event == "down" ) + { + if ( key == ' ') + { + mLastUpdateTime = 0; + update( 0.0f ); + }; + }; + } + else + { + //std::cerr << "MediaPluginExample::receiveMessage: unknown media message: " << message_string << std::endl; + }; + } + else + if ( message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER ) + { + if ( message_name == "browse_reload" ) + { + mLastUpdateTime = 0; + mFirstTime = true; + mStopAction = false; + update( 0.0f ); + } + else + if ( message_name == "browse_stop" ) + { + for( int n = 0; n < ENumObjects; ++n ) + mXInc[ n ] = mYInc[ n ] = 0; + + mStopAction = true; + update( 0.0f ); + } + else + { + //std::cerr << "MediaPluginExample::receiveMessage: unknown media_browser message: " << message_string << std::endl; + }; + } + else + { + //std::cerr << "MediaPluginExample::receiveMessage: unknown message class: " << message_class << std::endl; + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginExample::write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ) +{ + // make sure we don't write outside the buffer + if ( ( x < 0 ) || ( x >= mWidth ) || ( y < 0 ) || ( y >= mHeight ) ) + return; + + if ( mBackgroundPixels != NULL ) + { + unsigned char *pixel = mBackgroundPixels; + pixel += y * mWidth * mDepth; + pixel += ( x * mDepth ); + pixel[ 0 ] = b; + pixel[ 1 ] = g; + pixel[ 2 ] = r; + + setDirty( x, y, x + 1, y + 1 ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginExample::update( F64 milliseconds ) +{ + if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 ) + return; + + if ( mPixels == 0 ) + return; + + if ( mFirstTime ) + { + for( int n = 0; n < ENumObjects; ++n ) + { + mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 ); + mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 ); + + mColorR[ n ] = rand() % 0x60 + 0x60; + mColorG[ n ] = rand() % 0x60 + 0x60; + mColorB[ n ] = rand() % 0x60 + 0x60; + + mXInc[ n ] = 0; + while ( mXInc[ n ] == 0 ) + mXInc[ n ] = rand() % 7 - 3; + + mYInc[ n ] = 0; + while ( mYInc[ n ] == 0 ) + mYInc[ n ] = rand() % 9 - 4; + + mBlockSize[ n ] = rand() % 0x30 + 0x10; + }; + + delete [] mBackgroundPixels; + + mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ]; + + mFirstTime = false; + }; + + if ( mStopAction ) + return; + + if ( time( NULL ) > mLastUpdateTime + 3 ) + { + const int num_squares = rand() % 20 + 4; + int sqr1_r = rand() % 0x80 + 0x20; + int sqr1_g = rand() % 0x80 + 0x20; + int sqr1_b = rand() % 0x80 + 0x20; + int sqr2_r = rand() % 0x80 + 0x20; + int sqr2_g = rand() % 0x80 + 0x20; + int sqr2_b = rand() % 0x80 + 0x20; + + for ( int y1 = 0; y1 < num_squares; ++y1 ) + { + for ( int x1 = 0; x1 < num_squares; ++x1 ) + { + int px_start = mWidth * x1 / num_squares; + int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares; + int py_start = mHeight * y1 / num_squares; + int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares; + + for( int y2 = py_start; y2 < py_end; ++y2 ) + { + for( int x2 = px_start; x2 < px_end; ++x2 ) + { + int rowspan = mWidth * mDepth; + + if ( ( y1 % 2 ) ^ ( x1 % 2 ) ) + { + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b; + } + else + { + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b; + }; + }; + }; + }; + }; + + time( &mLastUpdateTime ); + }; + + memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth ); + + for( int n = 0; n < ENumObjects; ++n ) + { + if ( rand() % 50 == 0 ) + { + mXInc[ n ] = 0; + while ( mXInc[ n ] == 0 ) + mXInc[ n ] = rand() % 7 - 3; + + mYInc[ n ] = 0; + while ( mYInc[ n ] == 0 ) + mYInc[ n ] = rand() % 9 - 4; + }; + + if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] ) + mXInc[ n ] =- mXInc[ n ]; + + if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] ) + mYInc[ n ] =- mYInc[ n ]; + + mXpos[ n ] += mXInc[ n ]; + mYpos[ n ] += mYInc[ n ]; + + for( int y = 0; y < mBlockSize[ n ]; ++y ) + { + for( int x = 0; x < mBlockSize[ n ]; ++x ) + { + mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ]; + mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ]; + mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ]; + }; + }; + }; + + setDirty( 0, 0, mWidth, mHeight ); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +bool MediaPluginExample::init() +{ + LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" ); + message.setValue( "name", "Example Plugin" ); + sendMessage( message ); + + return true; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +int init_media_plugin( LLPluginInstance::sendMessageFunction host_send_func, + void* host_user_data, + LLPluginInstance::sendMessageFunction *plugin_send_func, + void **plugin_user_data ) +{ + MediaPluginExample* self = new MediaPluginExample( host_send_func, host_user_data ); + *plugin_send_func = MediaPluginExample::staticReceiveMessage; + *plugin_user_data = ( void* )self; + + return 0; +} diff --git a/linden/indra/media_plugins/gstreamer010/CMakeLists.txt b/linden/indra/media_plugins/gstreamer010/CMakeLists.txt new file mode 100644 index 000000000..4401e6407 --- /dev/null +++ b/linden/indra/media_plugins/gstreamer010/CMakeLists.txt @@ -0,0 +1,62 @@ +# -*- cmake -*- + +project(media_plugin_gstreamer010) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(MediaPluginBase) +include(FindOpenGL) + +include(GStreamer010Plugin) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} + ${GSTREAMER010_INCLUDE_DIRS} + ${GSTREAMER010_PLUGINS_BASE_INCLUDE_DIRS} +) + +### media_plugin_gstreamer010 + +set(media_plugin_gstreamer010_SOURCE_FILES + media_plugin_gstreamer010.cpp + llmediaimplgstreamervidplug.cpp + ) + +set(media_plugin_gstreamer010_HEADER_FILES + llmediaimplgstreamervidplug.h + llmediaimplgstreamertriviallogging.h + ) + +add_library(media_plugin_gstreamer010 + SHARED + ${media_plugin_gstreamer010_SOURCE_FILES} +) + +target_link_libraries(media_plugin_gstreamer010 + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${PLUGIN_API_WINDOWS_LIBRARIES} + ${GSTREAMER010_LIBRARIES} +) + +add_dependencies(media_plugin_gstreamer010 + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + + diff --git a/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h new file mode 100755 index 000000000..bfc443b9e --- /dev/null +++ b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h @@ -0,0 +1,60 @@ +/** + * @file llmediaimplgstreamer.h + * @author Tofu Linden + * @brief implementation that supports media playback via GStreamer. + * + * @cond + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +// header guard +#ifndef llmediaimplgstreamer_h +#define llmediaimplgstreamer_h + +#if LL_GSTREAMER010_ENABLED + +extern "C" { +#include <stdio.h> +#include <gst/gst.h> + +#include "apr_pools.h" +#include "apr_dso.h" +} + + +extern "C" { +gboolean llmediaimplgstreamer_bus_callback (GstBus *bus, + GstMessage *message, + gpointer data); +} + +#endif // LL_GSTREAMER010_ENABLED + +#endif // llmediaimplgstreamer_h diff --git a/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h new file mode 100755 index 000000000..bb90aa12f --- /dev/null +++ b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h @@ -0,0 +1,65 @@ +/** + * @file llmediaimplgstreamertriviallogging.h + * @brief minimal logging utilities. + * + * @cond + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ +#define __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ + +#include <cstdio> + +///////////////////////////////////////////////////////////////////////// +// Debug/Info/Warning macros. +#if LL_WINDOWS +#include <process.h> +#define LL_GETPID GetCurrentProcessId +#else +#include <sys/types.h> +#include <unistd.h> +#define LL_GETPID getpid +#endif +#define MSGMODULEFOO "(media plugin)" +#define STDERRMSG(...) do{\ + fprintf(stderr, " pid:%d: ", (int)LL_GETPID());\ + fprintf(stderr, MSGMODULEFOO " %s:%d: ", __FUNCTION__, __LINE__);\ + fprintf(stderr, __VA_ARGS__);\ + fputc('\n',stderr);\ + }while(0) +#define NULLMSG(...) do{}while(0) + +#define DEBUGMSG NULLMSG +#define INFOMSG STDERRMSG +#define WARNMSG STDERRMSG +///////////////////////////////////////////////////////////////////////// + +#endif /* __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ */ diff --git a/linden/indra/llmedia/llmediaimplgstreamervidplug.cpp b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp old mode 100644 new mode 100755 similarity index 72% rename from linden/indra/llmedia/llmediaimplgstreamervidplug.cpp rename to linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp index f2c0e8818..e194bf7c6 --- a/linden/indra/llmedia/llmediaimplgstreamervidplug.cpp +++ b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp @@ -2,9 +2,10 @@ * @file llmediaimplgstreamervidplug.h * @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl * + * @cond * $LicenseInfo:firstyear=2007&license=viewergpl$ * - * Copyright (c) 2007-2009, Linden Research, Inc. + * Copyright (c) 2007-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,13 +13,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * online at http://secondlife.com/developers/opensource/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * http://secondlife.com/developers/opensource/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -28,9 +29,11 @@ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ + * + * @endcond */ -///#if LL_GSTREAMER_ENABLED +#if LL_GSTREAMER010_ENABLED #include "linden_common.h" @@ -38,17 +41,18 @@ #include <gst/video/video.h> #include <gst/video/gstvideosink.h> -#include "llthread.h" +#include "llmediaimplgstreamertriviallogging.h" +// #include "llthread.h" #include "llmediaimplgstreamervidplug.h" GST_DEBUG_CATEGORY_STATIC (gst_slvideo_debug); #define GST_CAT_DEFAULT gst_slvideo_debug -/* Filter signals and args */ +/* Filter signals and args *//* enum { - /* FILL ME */ + *//* FILL ME *//* LAST_SIGNAL }; @@ -59,9 +63,13 @@ enum #define SLV_SIZECAPS ", width=(int){1,2,4,8,16,32,64,128,256,512,1024}, height=(int){1,2,4,8,16,32,64,128,256,512,1024} " #define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS ";" GST_VIDEO_CAPS_BGRx SLV_SIZECAPS +*/ + +#define SLV_SIZECAPS ", width=(int)[1,2048], height=(int)[1,2048] " +#define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( - "sink", + (gchar*)"sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS (SLV_ALLCAPS) @@ -115,11 +123,10 @@ gst_slvideo_show_frame (GstBaseSink * bsink, GstBuffer * buf) slvideo = GST_SLVIDEO(bsink); -#if 0 - fprintf(stderr, "\n\ntransferring a frame of %dx%d <- %p (%d)\n\n", - slvideo->width, slvideo->height, GST_BUFFER_DATA(buf), - slvideo->format); -#endif + DEBUGMSG("transferring a frame of %dx%d <- %p (%d)", + slvideo->width, slvideo->height, GST_BUFFER_DATA(buf), + slvideo->format); + if (GST_BUFFER_DATA(buf)) { // copy frame and frame info into neutral territory @@ -214,12 +221,13 @@ gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps) { GstSLVideo *filter; GstStructure *structure; - GstCaps *intersection; +// GstCaps *intersection; GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); filter = GST_SLVIDEO(bsink); - + +/* intersection = gst_caps_intersect (filter->caps, caps); if (gst_caps_is_empty (intersection)) { @@ -227,7 +235,7 @@ gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps) return FALSE; } gst_caps_unref(intersection); - +*/ int width = 0; int height = 0; gboolean ret; @@ -242,6 +250,10 @@ gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps) if (!ret) return FALSE; + INFOMSG("** filter caps set with width=%d, height=%d", width, height); + + GST_OBJECT_LOCK(filter); + filter->width = width; filter->height = height; filter->fps_n = gst_value_get_fraction_numerator(fps); @@ -256,8 +268,12 @@ gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps) filter->par_n = 1; filter->par_d = 1; } + GST_VIDEO_SINK_WIDTH(filter) = width; GST_VIDEO_SINK_HEIGHT(filter) = height; + + // crufty lump - we *always* accept *only* RGBX now. + /* filter->format = SLV_PF_UNKNOWN; if (0 == strcmp(gst_structure_get_name(structure), @@ -282,7 +298,12 @@ gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps) filter->format = SLV_PF_BGRX; //fprintf(stderr, "\n\nPIXEL FORMAT BGR\n\n"); } - } + + }*/ + + filter->format = SLV_PF_RGBX; + + GST_OBJECT_UNLOCK(filter); return TRUE; } @@ -317,6 +338,97 @@ gst_slvideo_stop (GstBaseSink * bsink) } +static GstFlowReturn +gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, + GstCaps * caps, GstBuffer ** buf) +{ + gint width, height; + GstStructure *structure = NULL; + GstSLVideo *slvideo; + slvideo = GST_SLVIDEO(bsink); + + // caps == requested caps + // we can ignore these and reverse-negotiate our preferred dimensions with + // the peer if we like - we need to do this to obey dynamic resize requests + // flowing in from the app. + structure = gst_caps_get_structure (caps, 0); + if (!gst_structure_get_int(structure, "width", &width) || + !gst_structure_get_int(structure, "height", &height)) + { + GST_WARNING_OBJECT (slvideo, "no width/height in caps %" GST_PTR_FORMAT, caps); + return GST_FLOW_NOT_NEGOTIATED; + } + + GstBuffer *newbuf = gst_buffer_new(); + bool made_bufferdata_ptr = false; +#define MAXDEPTHHACK 4 + + GST_OBJECT_LOCK(slvideo); + if (slvideo->resize_forced_always) // app is giving us a fixed size to work with + { + gint slwantwidth, slwantheight; + slwantwidth = slvideo->resize_try_width; + slwantheight = slvideo->resize_try_height; + + if (slwantwidth != width || + slwantheight != height) + { + // don't like requested caps, we will issue our own suggestion - copy + // the requested caps but substitute our own width and height and see + // if our peer is happy with that. + + GstCaps *desired_caps; + GstStructure *desired_struct; + desired_caps = gst_caps_copy (caps); + desired_struct = gst_caps_get_structure (desired_caps, 0); + + GValue value = {0}; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, slwantwidth); + gst_structure_set_value (desired_struct, "width", &value); + g_value_unset(&value); + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, slwantheight); + gst_structure_set_value (desired_struct, "height", &value); + + if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo), + desired_caps)) + { + // todo: re-use buffers from a pool? + // todo: set MALLOCDATA to null, set DATA to point straight to shm? + + // peer likes our cap suggestion + DEBUGMSG("peer loves us :)"); + GST_BUFFER_SIZE(newbuf) = slwantwidth * slwantheight * MAXDEPTHHACK; + GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); + GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); + gst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps); + + made_bufferdata_ptr = true; + } else { + // peer hates our cap suggestion + INFOMSG("peer hates us :("); + gst_caps_unref(desired_caps); + } + } + } + + GST_OBJECT_UNLOCK(slvideo); + + if (!made_bufferdata_ptr) // need to fallback to malloc at original size + { + GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK; + GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); + GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); + gst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps); + } + + *buf = GST_BUFFER_CAST(newbuf); + + return GST_FLOW_OK; +} + + /* initialize the plugin's class */ static void gst_slvideo_class_init (GstSLVideoClass * klass) @@ -338,7 +450,7 @@ gst_slvideo_class_init (GstSLVideoClass * klass) #define LLGST_DEBUG_FUNCPTR(p) (p) gstbasesink_class->get_caps = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_caps); gstbasesink_class->set_caps = LLGST_DEBUG_FUNCPTR( gst_slvideo_set_caps); - //gstbasesink_class->buffer_alloc=LLGST_DEBUG_FUNCPTR(gst_slvideo_buffer_alloc); + gstbasesink_class->buffer_alloc=LLGST_DEBUG_FUNCPTR(gst_slvideo_buffer_alloc); //gstbasesink_class->get_times = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_times); gstbasesink_class->preroll = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame); gstbasesink_class->render = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame); @@ -350,7 +462,7 @@ gst_slvideo_class_init (GstSLVideoClass * klass) #undef LLGST_DEBUG_FUNCPTR } - +/* static void gst_slvideo_update_caps (GstSLVideo * slvideo) { @@ -363,7 +475,7 @@ gst_slvideo_update_caps (GstSLVideo * slvideo) gst_caps_replace (&slvideo->caps, caps); } - +*/ /* initialize the new element * instantiate pads and add them to element @@ -374,6 +486,7 @@ static void gst_slvideo_init (GstSLVideo * filter, GstSLVideoClass * gclass) { + filter->caps = NULL; filter->width = -1; filter->height = -1; @@ -385,9 +498,14 @@ gst_slvideo_init (GstSLVideo * filter, filter->retained_frame_width = filter->width; filter->retained_frame_height = filter->height; filter->retained_frame_format = SLV_PF_UNKNOWN; + GstCaps *caps = gst_caps_from_string (SLV_ALLCAPS); + gst_caps_replace (&filter->caps, caps); + filter->resize_forced_always = false; + filter->resize_try_width = -1; + filter->resize_try_height = -1; GST_OBJECT_UNLOCK(filter); - gst_slvideo_update_caps(filter); + //gst_slvideo_update_caps(filter); } static void @@ -421,7 +539,7 @@ gst_slvideo_get_property (GObject * object, guint prop_id, static gboolean plugin_init (GstPlugin * plugin) { - //fprintf(stderr, "\n\n\nPLUGIN INIT\n\n\n"); + DEBUGMSG("PLUGIN INIT"); GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, (gchar*)"private-slvideo-plugin", 0, (gchar*)"Second Life Video Sink"); @@ -430,6 +548,12 @@ plugin_init (GstPlugin * plugin) GST_RANK_NONE, GST_TYPE_SLVIDEO); } +/* this is the structure that gstreamer looks for to register plugins + */ +/* NOTE: Can't rely upon GST_PLUGIN_DEFINE_STATIC to self-register, since + some g++ versions buggily avoid __attribute__((constructor)) functions - + so we provide an explicit plugin init function. + */ void gst_slvideo_init_class (void) { @@ -445,4 +569,4 @@ void gst_slvideo_init_class (void) (const gchar *)"http://www.secondlife.com/" ); } -///#endif // LL_GSTREAMER_ENABLED +#endif // LL_GSTREAMER010_ENABLED diff --git a/linden/indra/llmedia/llmediaimplgstreamervidplug.h b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h old mode 100644 new mode 100755 similarity index 86% rename from linden/indra/llmedia/llmediaimplgstreamervidplug.h rename to linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h index 3a984a9b7..5e8c72c98 --- a/linden/indra/llmedia/llmediaimplgstreamervidplug.h +++ b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h @@ -2,9 +2,10 @@ * @file llmediaimplgstreamervidplug.h * @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl * + * @cond * $LicenseInfo:firstyear=2007&license=viewergpl$ * - * Copyright (c) 2007-2009, Linden Research, Inc. + * Copyright (c) 2007-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,13 +13,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * online at http://secondlife.com/developers/opensource/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * http://secondlife.com/developers/opensource/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -28,18 +29,20 @@ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ + * + * @endcond */ #ifndef __GST_SLVIDEO_H__ #define __GST_SLVIDEO_H__ -///#if LL_GSTREAMER_ENABLED +#if LL_GSTREAMER010_ENABLED extern "C" { #include <gst/gst.h> #include <gst/video/video.h> #include <gst/video/gstvideosink.h> -#include <glib/gthread.h> +// #include <glib/gthread.h> } G_BEGIN_DECLS @@ -85,9 +88,13 @@ struct _GstSLVideo // when the retained frame is updated.) bool retained_frame_ready; // new frame ready since flag last reset. (*TODO: could get the writer to wait on a semaphore instead of having the reader poll, potentially making dropped frames somewhat cheaper.) unsigned char* retained_frame_data; - int retained_frame_allocbytes; - int retained_frame_width, retained_frame_height; + int retained_frame_allocbytes; + int retained_frame_width, retained_frame_height; SLVPixelFormat retained_frame_format; + // sticky resize info + bool resize_forced_always; + int resize_try_width; + int resize_try_height; }; struct _GstSLVideoClass @@ -101,6 +108,6 @@ void gst_slvideo_init_class (void); G_END_DECLS -///#endif // LL_GSTREAMER_ENABLED +#endif // LL_GSTREAMER010_ENABLED #endif /* __GST_SLVIDEO_H__ */ diff --git a/linden/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp b/linden/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp new file mode 100755 index 000000000..ed6d920d5 --- /dev/null +++ b/linden/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp @@ -0,0 +1,1386 @@ +/** + * @file media_plugin_gstreamer010.cpp + * @brief GStreamer-0.10 plugin for LLMedia API plugin system + * + * @cond + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" + +// Needed for _getcwd() RC +#ifdef LL_WINDOWS +#include <direct.h> +#include <stdlib.h> +#include <stdio.h> +#endif + +#ifdef LL_DARWIN +#include <Carbon/Carbon.h> +#endif + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#if LL_GSTREAMER010_ENABLED + +extern "C" { +#include <gst/gst.h> +#include <gst/gstelement.h> +} + +#include "llmediaimplgstreamer.h" +#include "llmediaimplgstreamertriviallogging.h" + +#include "llmediaimplgstreamervidplug.h" + +////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginGStreamer010 : public MediaPluginBase +{ +public: + MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginGStreamer010(); + + /* virtual */ void receiveMessage(const char *message_string); + + static bool startup(); + static bool closedown(); + + static void set_gst_plugin_path(); + + gboolean processGSTEvents(GstBus *bus, + GstMessage *message); + +private: + std::string getVersion(); + bool navigateTo( const std::string urlIn ); + bool seek( double time_sec ); + bool setVolume( float volume ); + + // misc + bool pause(); + bool stop(); + bool play(double rate); + bool getTimePos(double &sec_out); + + #define MIN_LOOP_SEC 1.0F + + bool mIsLooping; + + enum ECommand { + COMMAND_NONE, + COMMAND_STOP, + COMMAND_PLAY, + COMMAND_FAST_FORWARD, + COMMAND_FAST_REWIND, + COMMAND_PAUSE, + COMMAND_SEEK, + }; + ECommand mCommand; + +private: + bool unload(); + bool load(); + + bool update(int milliseconds); + void mouseDown( int x, int y ); + void mouseUp( int x, int y ); + void mouseMove( int x, int y ); + + void sizeChanged(); + + static bool mDoneInit; + + guint mBusWatchID; + + float mVolume; + + int mDepth; + + // media NATURAL size + int mNaturalWidth; + int mNaturalHeight; + // media current size + int mCurrentWidth; + int mCurrentHeight; + int mCurrentRowbytes; + // previous media size so we can detect changes + int mPreviousWidth; + int mPreviousHeight; + // desired render size from host + int mWidth; + int mHeight; + // padded texture size we need to write into + int mTextureWidth; + int mTextureHeight; + + int mTextureFormatPrimary; + int mTextureFormatType; + + bool mSeekWanted; + double mSeekDestination; + + std::string mLastTitle; + + // Very GStreamer-specific + GMainLoop *mPump; // event pump for this media + GstElement *mPlaybin; + GstSLVideo *mVideoSink; +}; + +//static +bool MediaPluginGStreamer010::mDoneInit = false; + +MediaPluginGStreamer010::MediaPluginGStreamer010( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) : + MediaPluginBase(host_send_func, host_user_data), + mBusWatchID ( 0 ), + mCurrentRowbytes ( 4 ), + mTextureFormatPrimary ( GL_RGBA ), + mTextureFormatType ( GL_UNSIGNED_INT_8_8_8_8_REV ), + mSeekWanted(false), + mSeekDestination(0.0), + mPump ( NULL ), + mPlaybin ( NULL ), + mVideoSink ( NULL ), + mCommand ( COMMAND_NONE ) +{ + std::ostringstream str; + INFOMSG("MediaPluginGStreamer010 constructor - my PID=%u", U32(LL_GETPID())); +} + +/////////////////////////////////////////////////////////////////////////////// +// +//#define LL_GST_REPORT_STATE_CHANGES +#ifdef LL_GST_REPORT_STATE_CHANGES +static char* get_gst_state_name(GstState state) +{ + switch (state) { + case GST_STATE_VOID_PENDING: return "VOID_PENDING"; + case GST_STATE_NULL: return "NULL"; + case GST_STATE_READY: return "READY"; + case GST_STATE_PAUSED: return "PAUSED"; + case GST_STATE_PLAYING: return "PLAYING"; + } + return "(unknown)"; +} +#endif // LL_GST_REPORT_STATE_CHANGES + +gboolean +MediaPluginGStreamer010::processGSTEvents(GstBus *bus, + GstMessage *message) +{ + if (!message) + return TRUE; // shield against GStreamer bug + + if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STATE_CHANGED && + GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING) + { + DEBUGMSG("Got GST message type: %s", + GST_MESSAGE_TYPE_NAME (message)); + } + else + { + // TODO: grok 'duration' message type + DEBUGMSG("Got GST message type: %s", + GST_MESSAGE_TYPE_NAME (message)); + } + + switch (GST_MESSAGE_TYPE (message)) + { + case GST_MESSAGE_BUFFERING: + { + // NEEDS GST 0.10.11+ and America discovered by C.Columbus + gint percent = 0; + gst_message_parse_buffering(message, &percent); + DEBUGMSG("GST buffering: %d%%", percent); + + break; + } + case GST_MESSAGE_STATE_CHANGED: { + GstState old_state; + GstState new_state; + GstState pending_state; + gst_message_parse_state_changed(message, + &old_state, + &new_state, + &pending_state); + #ifdef LL_GST_REPORT_STATE_CHANGES + // not generally very useful, and rather spammy. + DEBUGMSG("state change (old,<new>,pending): %s,<%s>,%s", + get_gst_state_name(old_state), + get_gst_state_name(new_state), + get_gst_state_name(pending_state)); + #endif // LL_GST_REPORT_STATE_CHANGES + + switch (new_state) + { + case GST_STATE_VOID_PENDING: + break; + case GST_STATE_NULL: + break; + case GST_STATE_READY: + setStatus(STATUS_LOADED); + break; + case GST_STATE_PAUSED: + setStatus(STATUS_PAUSED); + break; + case GST_STATE_PLAYING: + setStatus(STATUS_PLAYING); + break; + } + break; + } + case GST_MESSAGE_ERROR: + { + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_error (message, &err, &debug); + WARNMSG("GST error: %s", err?err->message:"(unknown)"); + if (err) + g_error_free (err); + g_free (debug); + + mCommand = COMMAND_STOP; + + setStatus(STATUS_ERROR); + + break; + } + case GST_MESSAGE_INFO: + { + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_info (message, &err, &debug); + INFOMSG("GST info: %s", err?err->message:"(unknown)"); + if (err) + g_error_free (err); + g_free (debug); + + break; + } + case GST_MESSAGE_WARNING: + { + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_warning (message, &err, &debug); + WARNMSG("GST warning: %s", err?err->message:"(unknown)"); + if (err) + g_error_free (err); + g_free (debug); + + break; + } + case GST_MESSAGE_TAG: + { + GstTagList *new_tags; + + gst_message_parse_tag( message, &new_tags ); + + gchar *title = NULL; + + if ( gst_tag_list_get_string(new_tags, GST_TAG_TITLE, &title) ) + { + //WARMING("Title: %s", title); + std::string newtitle(title); + gst_tag_list_free(new_tags); + + if ( newtitle != mLastTitle && !newtitle.empty() ) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); + message.setValue("name", newtitle ); + sendMessage( message ); + mLastTitle = newtitle; + } + g_free(title); + } + + break; + } + case GST_MESSAGE_EOS: + { + /* end-of-stream */ + DEBUGMSG("GST end-of-stream."); + if (mIsLooping) + { + DEBUGMSG("looping media..."); + double eos_pos_sec = 0.0F; + bool got_eos_position = getTimePos(eos_pos_sec); + + if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC) + { + // if we know that the movie is really short, don't + // loop it else it can easily become a time-hog + // because of GStreamer spin-up overhead + DEBUGMSG("really short movie (%0.3fsec) - not gonna loop this, pausing instead.", eos_pos_sec); + // inject a COMMAND_PAUSE + mCommand = COMMAND_PAUSE; + } + else + { + #undef LLGST_LOOP_BY_SEEKING + // loop with a stop-start instead of a seek, because it actually seems rather + // faster than seeking on remote streams. + #ifdef LLGST_LOOP_BY_SEEKING + // first, try looping by an explicit rewind + bool seeksuccess = seek(0.0); + if (seeksuccess) + { + play(1.0); + } + else + #endif // LLGST_LOOP_BY_SEEKING + { // use clumsy stop-start to loop + DEBUGMSG("didn't loop by rewinding - stopping and starting instead..."); + stop(); + play(1.0); + } + } + } + else // not a looping media + { + // inject a COMMAND_STOP + mCommand = COMMAND_STOP; + } + } break; + + default: + /* unhandled message */ + break; + } + + /* we want to be notified again the next time there is a message + * on the bus, so return true (false means we want to stop watching + * for messages on the bus and our callback should not be called again) + */ + return TRUE; +} + +extern "C" { +gboolean +llmediaimplgstreamer_bus_callback (GstBus *bus, + GstMessage *message, + gpointer data) +{ + MediaPluginGStreamer010 *impl = (MediaPluginGStreamer010*)data; + return impl->processGSTEvents(bus, message); +} +} // extern "C" + + + +bool +MediaPluginGStreamer010::navigateTo ( const std::string urlIn ) +{ + if (!mDoneInit) + return false; // error + + setStatus(STATUS_LOADING); + + DEBUGMSG("Setting media URI: %s", urlIn.c_str()); + + mSeekWanted = false; + + if (NULL == mPump || + NULL == mPlaybin) + { + setStatus(STATUS_ERROR); + return false; // error + } + + // set URI + g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL); + //g_object_set (G_OBJECT (mPlaybin), "uri", "file:///tmp/movie", NULL); + + // navigateTo implicitly plays, too. + play(1.0); + + return true; +} + + +bool +MediaPluginGStreamer010::update(int milliseconds) +{ + if (!mDoneInit) + return false; // error + + DEBUGMSG("updating media..."); + + // sanity check + if (NULL == mPump || + NULL == mPlaybin) + { + DEBUGMSG("dead media..."); + return false; + } + + // see if there's an outstanding seek wanted + if (mSeekWanted && + // bleh, GST has to be happy that the movie is really truly playing + // or it may quietly ignore the seek (with rtsp:// at least). + (GST_STATE(mPlaybin) == GST_STATE_PLAYING)) + { + seek(mSeekDestination); + mSeekWanted = false; + } + + // *TODO: time-limit - but there isn't a lot we can do here, most + // time is spent in gstreamer's own opaque worker-threads. maybe + // we can do something sneaky like only unlock the video object + // for 'milliseconds' and otherwise hold the lock. + while (g_main_context_pending(g_main_loop_get_context(mPump))) + { + g_main_context_iteration(g_main_loop_get_context(mPump), FALSE); + } + + // check for availability of a new frame + + if (mVideoSink) + { + GST_OBJECT_LOCK(mVideoSink); + if (mVideoSink->retained_frame_ready) + { + DEBUGMSG("NEW FRAME READY"); + + if (mVideoSink->retained_frame_width != mCurrentWidth || + mVideoSink->retained_frame_height != mCurrentHeight) + // *TODO: also check for change in format + { + // just resize container, don't consume frame + int neww = mVideoSink->retained_frame_width; + int newh = mVideoSink->retained_frame_height; + + int newd = 4; + mTextureFormatPrimary = GL_RGBA; + mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; + + /* + int newd = SLVPixelFormatBytes[mVideoSink->retained_frame_format]; + if (SLV_PF_BGRX == mVideoSink->retained_frame_format) + { + mTextureFormatPrimary = GL_BGRA; + mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; + } + else + { + mTextureFormatPrimary = GL_RGBA; + mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; + } + */ + + GST_OBJECT_UNLOCK(mVideoSink); + + mCurrentRowbytes = neww * newd; + DEBUGMSG("video container resized to %dx%d", + neww, newh); + + mDepth = newd; + mCurrentWidth = neww; + mCurrentHeight = newh; + sizeChanged(); + return true; + } + + if (mPixels && + mCurrentHeight <= mHeight && + mCurrentWidth <= mWidth && + !mTextureSegmentName.empty()) + { + // we're gonna totally consume this frame - reset 'ready' flag + mVideoSink->retained_frame_ready = FALSE; + int destination_rowbytes = mWidth * mDepth; + for (int row=0; row<mCurrentHeight; ++row) + { + memcpy(&mPixels + [destination_rowbytes * row], + &mVideoSink->retained_frame_data + [mCurrentRowbytes * row], + mCurrentRowbytes); + } + + GST_OBJECT_UNLOCK(mVideoSink); + DEBUGMSG("NEW FRAME REALLY TRULY CONSUMED, TELLING HOST"); + + setDirty(0,0,mCurrentWidth,mCurrentHeight); + } + else + { + // new frame ready, but we're not ready to + // consume it. + + GST_OBJECT_UNLOCK(mVideoSink); + + DEBUGMSG("NEW FRAME not consumed, still waiting for a shm segment and/or shm resize"); + } + + return true; + } + else + { + // nothing to do yet. + GST_OBJECT_UNLOCK(mVideoSink); + return true; + } + } + + return true; +} + + +void +MediaPluginGStreamer010::mouseDown( int x, int y ) +{ + // do nothing +} + +void +MediaPluginGStreamer010::mouseUp( int x, int y ) +{ + // do nothing +} + +void +MediaPluginGStreamer010::mouseMove( int x, int y ) +{ + // do nothing +} + + +bool +MediaPluginGStreamer010::pause() +{ + DEBUGMSG("pausing media..."); + // todo: error-check this? + gst_element_set_state(mPlaybin, GST_STATE_PAUSED); + return true; +} + +bool +MediaPluginGStreamer010::stop() +{ + DEBUGMSG("stopping media..."); + // todo: error-check this? + gst_element_set_state(mPlaybin, GST_STATE_READY); + return true; +} + +bool +MediaPluginGStreamer010::play(double rate) +{ + // NOTE: we don't actually support non-natural rate. + + DEBUGMSG("playing media... rate=%f", rate); + // todo: error-check this? + gst_element_set_state(mPlaybin, GST_STATE_PLAYING); + return true; +} + +bool +MediaPluginGStreamer010::setVolume( float volume ) +{ + // we try to only update volume as conservatively as + // possible, as many gst-plugins-base versions up to at least + // November 2008 have critical race-conditions in setting volume - sigh + if (mVolume == volume) + return true; // nothing to do, everything's fine + + mVolume = volume; + if (mDoneInit && mPlaybin) + { + g_object_set(mPlaybin, "volume", mVolume, NULL); + return true; + } + + return false; +} + +bool +MediaPluginGStreamer010::seek(double time_sec) +{ + bool success = false; + if (mDoneInit && mPlaybin) + { + success = gst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, + GstSeekFlags(GST_SEEK_FLAG_FLUSH | + GST_SEEK_FLAG_KEY_UNIT), + GST_SEEK_TYPE_SET, gint64(time_sec*GST_SECOND), + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + } + DEBUGMSG("MEDIA SEEK REQUEST to %fsec result was %d", + float(time_sec), int(success)); + return success; +} + +bool +MediaPluginGStreamer010::getTimePos(double &sec_out) +{ + bool got_position = false; + if (mPlaybin) + { + gint64 pos; + GstFormat timefmt = GST_FORMAT_TIME; + got_position = gst_element_query_position(mPlaybin, + &timefmt, + &pos); + got_position = got_position + && (timefmt == GST_FORMAT_TIME); + // GStreamer may have other ideas, but we consider the current position + // undefined if not PLAYING or PAUSED + got_position = got_position && + (GST_STATE(mPlaybin) == GST_STATE_PLAYING || + GST_STATE(mPlaybin) == GST_STATE_PAUSED); + if (got_position && !GST_CLOCK_TIME_IS_VALID(pos)) + { + if (GST_STATE(mPlaybin) == GST_STATE_PLAYING) + { + // if we're playing then we treat an invalid clock time + // as 0, for complicated reasons (insert reason here) + pos = 0; + } + else + { + got_position = false; + } + + } + // If all the preconditions succeeded... we can trust the result. + if (got_position) + { + sec_out = double(pos) / double(GST_SECOND); // gst to sec + } + } + return got_position; +} + +bool +MediaPluginGStreamer010::load() +{ + if (!mDoneInit) + return false; // error + + setStatus(STATUS_LOADING); + + DEBUGMSG("setting up media..."); + + mIsLooping = false; + mVolume = (float) 0.1234567; // minor hack to force an initial volume update + + // Create a pumpable main-loop for this media + mPump = g_main_loop_new (NULL, FALSE); + if (!mPump) + { + setStatus(STATUS_ERROR); + return false; // error + } + + // instantiate a playbin element to do the hard work + mPlaybin = gst_element_factory_make ("playbin", "play"); + if (!mPlaybin) + { + setStatus(STATUS_ERROR); + return false; // error + } + + // get playbin's bus + GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); + if (!bus) + { + setStatus(STATUS_ERROR); + return false; // error + } + mBusWatchID = gst_bus_add_watch (bus, + llmediaimplgstreamer_bus_callback, + this); + gst_object_unref (bus); + + if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) { + // instantiate a custom video sink + mVideoSink = + GST_SLVIDEO(gst_element_factory_make ("private-slvideo", "slvideo")); + if (!mVideoSink) + { + WARNMSG("Could not instantiate private-slvideo element."); + // todo: cleanup. + setStatus(STATUS_ERROR); + return false; // error + } + + // connect the pieces + g_object_set(mPlaybin, "video-sink", mVideoSink, NULL); + } + + return true; +} + +bool +MediaPluginGStreamer010::unload () +{ + if (!mDoneInit) + return false; // error + + DEBUGMSG("unloading media..."); + + // stop getting callbacks for this bus + g_source_remove(mBusWatchID); + mBusWatchID = 0; + + if (mPlaybin) + { + gst_element_set_state (mPlaybin, GST_STATE_NULL); + gst_object_unref (GST_OBJECT (mPlaybin)); + mPlaybin = NULL; + } + + if (mPump) + { + g_main_loop_quit(mPump); + mPump = NULL; + } + + mVideoSink = NULL; + + setStatus(STATUS_NONE); + + return true; +} + + +//static +bool +MediaPluginGStreamer010::startup() +{ + // first - check if GStreamer is explicitly disabled + if (NULL != getenv("LL_DISABLE_GSTREAMER")) + return false; + + // only do global GStreamer initialization once. + if (!mDoneInit) + { + g_thread_init(NULL); + + // Init the glib type system - we need it. + g_type_init(); + set_gst_plugin_path(); + + +/* + // Get symbols! +#if LL_DARWIN + if (! grab_gst_syms("libgstreamer-0.10.dylib", + "libgstvideo-0.10.dylib") ) +#elseif LL_WINDOWS + if (! grab_gst_syms("libgstreamer-0.10.dll", + "libgstvideo-0.10.dll") ) +#else // linux or other ELFy unixoid + if (! grab_gst_syms("libgstreamer-0.10.so.0", + "libgstvideo-0.10.so.0") ) +#endif + { + WARNMSG("Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled."); + return false; + } +*/ +// if (gst_segtrap_set_enabled) +// { + gst_segtrap_set_enabled(FALSE); +// } +// else +// { +// WARNMSG("gst_segtrap_set_enabled() is not available; plugin crashes won't be caught."); +// } +/* +#if LL_LINUX + // Gstreamer tries a fork during init, waitpid-ing on it, + // which conflicts with any installed SIGCHLD handler... + struct sigaction tmpact, oldact; + if (gst_registry_fork_set_enabled) { + // if we can disable SIGCHLD-using forking behaviour, + // do it. + gst_registry_fork_set_enabled(false); + } + else { + // else temporarily install default SIGCHLD handler + // while GStreamer initialises + tmpact.sa_handler = SIG_DFL; + sigemptyset( &tmpact.sa_mask ); + tmpact.sa_flags = SA_SIGINFO; + sigaction(SIGCHLD, &tmpact, &oldact); + } +#endif // LL_LINUX +*/ + // Protect against GStreamer resetting the locale, yuck. + static std::string saved_locale; + saved_locale = setlocale(LC_ALL, NULL); + + // finally, try to initialize GStreamer! + GError *err = NULL; + gboolean init_gst_success = gst_init_check(NULL, NULL, &err); + + // restore old locale + setlocale(LC_ALL, saved_locale.c_str() ); +/* +#if LL_LINUX + // restore old SIGCHLD handler + if (!gst_registry_fork_set_enabled) + sigaction(SIGCHLD, &oldact, NULL); +#endif // LL_LINUX +*/ + if (!init_gst_success) // fail + { + if (err) + { + WARNMSG("GST init failed: %s", err->message); + g_error_free(err); + } + else + { + WARNMSG("GST init failed for unspecified reason."); + } + return false; + } + + // Set up logging facilities + gst_debug_remove_log_function( gst_debug_log_default ); +// gst_debug_add_log_function( gstreamer_log, NULL ); + + // Init our custom plugins - only really need do this once. + gst_slvideo_init_class(); +/* + // List the plugins GStreamer can find + LL_DEBUGS("MediaImpl") << "Found GStreamer plugins:" << LL_ENDL; + GList *list; + GstRegistry *registry = gst_registry_get_default(); + std::string loaded = ""; + for (list = gst_registry_get_plugin_list(registry); + list != NULL; + list = g_list_next(list)) + { + GstPlugin *list_plugin = (GstPlugin *)list->data; + (bool)gst_plugin_is_loaded(list_plugin) ? loaded = "Yes" : loaded = "No"; + LL_DEBUGS("MediaImpl") << gst_plugin_get_name(list_plugin) << ", loaded? " << loaded << LL_ENDL; + } + gst_plugin_list_free(list); +*/ + mDoneInit = true; + } + + return true; +} + +void MediaPluginGStreamer010::set_gst_plugin_path() +{ + // Linux sets GST_PLUGIN_PATH in wrapper.sh, not here. +#if LL_WINDOWS || LL_DARWIN + + std::string imp_dir = ""; + + // Get the current working directory: +#if LL_WINDOWS + char* raw_dir; + raw_dir = _getcwd(NULL,0); + if( raw_dir != NULL ) + { + imp_dir = std::string( raw_dir ); + } +#elif LL_DARWIN + CFBundleRef main_bundle = CFBundleGetMainBundle(); + if( main_bundle != NULL ) + { + CFURLRef bundle_url = CFBundleCopyBundleURL( main_bundle ); + if( bundle_url != NULL ) + { + #ifndef MAXPATHLEN + #define MAXPATHLEN 1024 + #endif + char raw_dir[MAXPATHLEN]; + if( CFURLGetFileSystemRepresentation( bundle_url, true, (UInt8 *)raw_dir, MAXPATHLEN) ) + { + imp_dir = std::string( raw_dir ) + "/Contents/MacOS/"; + } + CFRelease(bundle_url); + } + } +#endif + + if( imp_dir == "" ) + { + WARNMSG("Could not get application directory, not setting GST_PLUGIN_PATH."); + return; + } + + DEBUGMSG("Imprudence is installed at %s", imp_dir); + + // ":" on Mac and 'Nix, ";" on Windows + std::string separator = G_SEARCHPATH_SEPARATOR_S; + + // Grab the current path, if it's set. + std::string old_plugin_path = ""; + char *old_path = getenv("GST_PLUGIN_PATH"); + if(old_path == NULL) + { + DEBUGMSG("Did not find user-set GST_PLUGIN_PATH."); + } + else + { + old_plugin_path = separator + std::string( old_path ); + } + + + // Search both Imprudence and Imprudence\lib\gstreamer-plugins. + // But we also want to search the path the user has set, if any. + std::string plugin_path = + "GST_PLUGIN_PATH=" + +#if LL_WINDOWS + imp_dir + "\\lib\\gstreamer-plugins" + +#elif LL_DARWIN + imp_dir + separator + + imp_dir + "/../Resources/lib/gstreamer-plugins" + +#endif + old_plugin_path; + + int put_result; + + // Place GST_PLUGIN_PATH in the environment settings +#if LL_WINDOWS + put_result = _putenv( (char*)plugin_path.c_str() ); +#elif LL_DARWIN + put_result = putenv( (char*)plugin_path.c_str() ); +#endif + + if( put_result == -1 ) + { + WARNMSG("Setting GST_PLUGIN_PATH failed!"); + } + else + { + DEBUGMSG("GST_PLUGIN_PATH set to %s", getenv("GST_PLUGIN_PATH")); + } + + // Don't load system plugins. We only want to use ours, to avoid conflicts. +#if LL_WINDOWS + put_result = _putenv( "GST_PLUGIN_SYSTEM_PATH=\"\"" ); +#elif LL_DARWIN + put_result = putenv( "GST_PLUGIN_SYSTEM_PATH=\"\"" ); +#endif + + if( put_result == -1 ) + { + WARNMSG("Setting GST_PLUGIN_SYSTEM_PATH=\"\" failed!"); + } + +#endif // LL_WINDOWS || LL_DARWIN +} + + +void +MediaPluginGStreamer010::sizeChanged() +{ + // the shared writing space has possibly changed size/location/whatever + + // Check to see whether the movie's NATURAL size has been set yet + if (1 == mNaturalWidth && + 1 == mNaturalHeight) + { + mNaturalWidth = mCurrentWidth; + mNaturalHeight = mCurrentHeight; + DEBUGMSG("Media NATURAL size better detected as %dx%d", + mNaturalWidth, mNaturalHeight); + } + + // if the size has changed then the shm has changed and the app needs telling + if (mCurrentWidth != mPreviousWidth || + mCurrentHeight != mPreviousHeight) + { + mPreviousWidth = mCurrentWidth; + mPreviousHeight = mCurrentHeight; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); + message.setValue("name", mTextureSegmentName); + message.setValueS32("width", mNaturalWidth); + message.setValueS32("height", mNaturalHeight); + DEBUGMSG("<--- Sending size change request to application with name: '%s' - natural size is %d x %d", mTextureSegmentName.c_str(), mNaturalWidth, mNaturalHeight); + sendMessage(message); + } +} + + + +//static +bool +MediaPluginGStreamer010::closedown() +{ + if (!mDoneInit) + return false; // error + +// ungrab_gst_syms(); + + mDoneInit = false; + + return true; +} + +MediaPluginGStreamer010::~MediaPluginGStreamer010() +{ + DEBUGMSG("MediaPluginGStreamer010 destructor"); + + closedown(); + + DEBUGMSG("GStreamer010 closing down"); +} + + +std::string +MediaPluginGStreamer010::getVersion() +{ + std::string plugin_version = "GStreamer010 media plugin, GStreamer version "; + if (mDoneInit) // && gst_version) + { + guint major, minor, micro, nano; + gst_version(&major, &minor, µ, &nano); + plugin_version += llformat("%u.%u.%u.%u (runtime), %u.%u.%u.%u (headers)", (unsigned int)major, (unsigned int)minor, (unsigned int)micro, (unsigned int)nano, (unsigned int)GST_VERSION_MAJOR, (unsigned int)GST_VERSION_MINOR, (unsigned int)GST_VERSION_MICRO, (unsigned int)GST_VERSION_NANO); + } + else + { + plugin_version += "(unknown)"; + } + return plugin_version; +} + +void MediaPluginGStreamer010::receiveMessage(const char *message_string) +{ + //std::cerr << "MediaPluginGStreamer010::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; + message.setValueLLSD("versions", versions); + + if ( load() ) + { + DEBUGMSG("GStreamer010 media instance set up"); + } + else + { + WARNMSG("GStreamer010 media instance failed to set up"); + } + + message.setValue("plugin_version", getVersion()); + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + double time = message_in.getValueReal("time"); + + // Convert time to milliseconds for update() + update((int)(time * 1000.0f)); + } + else if(message_name == "cleanup") + { + unload(); + closedown(); + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + + std::ostringstream str; + INFOMSG("MediaPluginGStreamer010::receiveMessage: shared memory added, name: %s, size: %d, address: %p", name.c_str(), int(info.mSize), info.mAddress); + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + + DEBUGMSG("MediaPluginGStreamer010::receiveMessage: shared memory remove, name = %s", name.c_str()); + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + + // Make sure the movie decoder is no longer pointed at the shared segment. + sizeChanged(); + } + mSharedSegments.erase(iter); + } + else + { + WARNMSG("MediaPluginGStreamer010::receiveMessage: unknown shared memory region!"); + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { + std::ostringstream str; + INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown base message: %s", message_name.c_str()); + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "init") + { + // Plugin gets to decide the texture parameters to use. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + // lame to have to decide this now, it depends on the movie. Oh well. + mDepth = 4; + + mCurrentWidth = 1; + mCurrentHeight = 1; + mPreviousWidth = 1; + mPreviousHeight = 1; + mNaturalWidth = 1; + mNaturalHeight = 1; + mWidth = 1; + mHeight = 1; + mTextureWidth = 1; + mTextureHeight = 1; + + message.setValueU32("format", GL_RGBA); + message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV); + + message.setValueS32("depth", mDepth); + message.setValueS32("default_width", mWidth); + message.setValueS32("default_height", mHeight); + message.setValueU32("internalformat", GL_RGBA8); + message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. + message.setValueBoolean("allow_downsample", true); // we respond with grace and performance if asked to downscale + sendMessage(message); + } + else if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + std::ostringstream str; + INFOMSG("---->Got size change instruction from application with shm name: %s - size is %d x %d", name.c_str(), width, height); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + INFOMSG("*** Got size change with matching shm, new size is %d x %d", width, height); + INFOMSG("*** Got size change with matching shm, texture size size is %d x %d", texture_width, texture_height); + + mPixels = (unsigned char*)iter->second.mAddress; + mTextureSegmentName = name; + mWidth = width; + mHeight = height; + + if (texture_width > 1 || + texture_height > 1) // not a dummy size from the app, a real explicit forced size + { + INFOMSG("**** = REAL RESIZE REQUEST FROM APP"); + + GST_OBJECT_LOCK(mVideoSink); + mVideoSink->resize_forced_always = true; + mVideoSink->resize_try_width = texture_width; + mVideoSink->resize_try_height = texture_height; + GST_OBJECT_UNLOCK(mVideoSink); + } + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + } + } + } + else if(message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + navigateTo( uri ); + sendStatus(); + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + + if(event == "down") + { + mouseDown(x, y); + } + else if(event == "up") + { + mouseUp(x, y); + } + else if(event == "move") + { + mouseMove(x, y); + }; + }; + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if(message_name == "stop") + { + stop(); + } + else if(message_name == "start") + { + double rate = 0.0; + if(message_in.hasValue("rate")) + { + rate = message_in.getValueReal("rate"); + } + // NOTE: we don't actually support rate. + play(rate); + } + else if(message_name == "pause") + { + pause(); + } + else if(message_name == "seek") + { + double time = message_in.getValueReal("time"); + // defer the actual seek in case we haven't + // really truly started yet in which case there + // is nothing to seek upon + mSeekWanted = true; + mSeekDestination = time; + } + else if(message_name == "set_loop") + { + bool loop = message_in.getValueBoolean("loop"); + mIsLooping = loop; + } + else if(message_name == "set_volume") + { + double volume = message_in.getValueReal("volume"); + setVolume(volume); + } + } + else + { + INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown message class: %s", message_class.c_str()); + } + } +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + if (MediaPluginGStreamer010::startup()) + { + MediaPluginGStreamer010 *self = new MediaPluginGStreamer010(host_send_func, host_user_data); + *plugin_send_func = MediaPluginGStreamer010::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; // okay + } + else + { + return -1; // failed to init + } +} + +#else // LL_GSTREAMER010_ENABLED + +// Stubbed-out class with constructor/destructor (necessary or windows linker +// will just think its dead code and optimize it all out) +class MediaPluginGStreamer010 : public MediaPluginBase +{ +public: + MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginGStreamer010(); + /* virtual */ void receiveMessage(const char *message_string); +}; + +MediaPluginGStreamer010::MediaPluginGStreamer010( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) : + MediaPluginBase(host_send_func, host_user_data) +{ + // no-op +} + +MediaPluginGStreamer010::~MediaPluginGStreamer010() +{ + // no-op +} + +void MediaPluginGStreamer010::receiveMessage(const char *message_string) +{ + // no-op +} + +// We're building without GStreamer enabled. Just refuse to initialize. +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + return -1; +} + +#endif // LL_GSTREAMER010_ENABLED diff --git a/linden/indra/media_plugins/quicktime/CMakeLists.txt b/linden/indra/media_plugins/quicktime/CMakeLists.txt new file mode 100755 index 000000000..df191f543 --- /dev/null +++ b/linden/indra/media_plugins/quicktime/CMakeLists.txt @@ -0,0 +1,92 @@ +# -*- cmake -*- + +project(media_plugin_quicktime) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(MediaPluginBase) +include(FindOpenGL) +include(QuickTimePlugin) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} +) + +if (DARWIN) + include(CMakeFindFrameworks) + find_library(CARBON_LIBRARY Carbon) +endif (DARWIN) + + +### media_plugin_quicktime + +set(media_plugin_quicktime_SOURCE_FILES + media_plugin_quicktime.cpp + ) + +add_library(media_plugin_quicktime + SHARED + ${media_plugin_quicktime_SOURCE_FILES} +) + +target_link_libraries(media_plugin_quicktime + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${QUICKTIME_LIBRARY} + ${PLUGIN_API_WINDOWS_LIBRARIES} +) + +add_dependencies(media_plugin_quicktime + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + +if (WINDOWS) + set_target_properties( + media_plugin_quicktime + PROPERTIES + LINK_FLAGS "/MANIFEST:NO /NODEFAULTLIB:LIBCMT" + LINK_FLAGS_DEBUG "/MANIFEST:NO /NODEFAULTLIB:\"LIBCMT;LIBCMTD\"" + ) +endif (WINDOWS) + +if (QUICKTIME) + + add_definitions(-DLL_QUICKTIME_ENABLED=1) + + if (DARWIN) + # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name + set_target_properties( + media_plugin_quicktime + PROPERTIES + PREFIX "" + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" + ) + +# We use a bunch of deprecated system APIs. + set_source_files_properties( + media_plugin_quicktime.cpp PROPERTIES + COMPILE_FLAGS -Wno-deprecated-declarations + ) + find_library(CARBON_LIBRARY Carbon) + target_link_libraries(media_plugin_quicktime ${CARBON_LIBRARY}) + endif (DARWIN) +endif (QUICKTIME) + diff --git a/linden/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/linden/indra/media_plugins/quicktime/media_plugin_quicktime.cpp new file mode 100755 index 000000000..999f754dc --- /dev/null +++ b/linden/indra/media_plugins/quicktime/media_plugin_quicktime.cpp @@ -0,0 +1,1111 @@ +/** + * @file media_plugin_quicktime.cpp + * @brief QuickTime plugin for LLMedia API plugin system + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * @endcond + */ + +#include "linden_common.h" + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#if LL_QUICKTIME_ENABLED + +#if defined(LL_DARWIN) + #include <QuickTime/QuickTime.h> +#elif defined(LL_WINDOWS) + #include "MacTypes.h" + #include "QTML.h" + #include "Movies.h" + #include "QDoffscreen.h" + #include "FixMath.h" + #include "QTLoadLibraryUtils.h" +#endif + +// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginQuickTime : public MediaPluginBase +{ +public: + MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginQuickTime(); + + /* virtual */ void receiveMessage(const char *message_string); + +private: + + int mNaturalWidth; + int mNaturalHeight; + Movie mMovieHandle; + GWorldPtr mGWorldHandle; + ComponentInstance mMovieController; + int mCurVolume; + bool mMediaSizeChanging; + bool mIsLooping; + std::string mMovieTitle; + bool mReceivedTitle; + const int mMinWidth; + const int mMaxWidth; + const int mMinHeight; + const int mMaxHeight; + F64 mPlayRate; + std::string mNavigateURL; + + enum ECommand { + COMMAND_NONE, + COMMAND_STOP, + COMMAND_PLAY, + COMMAND_FAST_FORWARD, + COMMAND_FAST_REWIND, + COMMAND_PAUSE, + COMMAND_SEEK, + }; + ECommand mCommand; + + // Override this to add current time and duration to the message + /*virtual*/ void setDirty(int left, int top, int right, int bottom) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated"); + + message.setValueS32("left", left); + message.setValueS32("top", top); + message.setValueS32("right", right); + message.setValueS32("bottom", bottom); + + if(mMovieHandle) + { + message.setValueReal("current_time", getCurrentTime()); + message.setValueReal("duration", getDuration()); + message.setValueReal("current_rate", Fix2X(GetMovieRate(mMovieHandle))); + } + + sendMessage(message); + } + + + static Rect rectFromSize(int width, int height) + { + Rect result; + + + result.left = 0; + result.top = 0; + result.right = width; + result.bottom = height; + + return result; + } + + Fixed getPlayRate(void) + { + Fixed result; + if(mPlayRate == 0.0f) + { + // Default to the movie's preferred rate + result = GetMoviePreferredRate(mMovieHandle); + if(result == 0) + { + // Don't return a 0 play rate, ever. + std::cerr << "Movie's preferred rate is 0, forcing to 1.0." << std::endl; + result = X2Fix(1.0f); + } + } + else + { + result = X2Fix(mPlayRate); + } + + return result; + } + + void load( const std::string url ) + { + + if ( url.empty() ) + return; + + // Stop and unload any existing movie before starting another one. + unload(); + + setStatus(STATUS_LOADING); + + //In case std::string::c_str() makes a copy of the url data, + //make sure there is memory to hold it before allocating memory for handle. + //if fails, NewHandleClear(...) should return NULL. + const char* url_string = url.c_str() ; + Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) ); + + if ( NULL == handle || noErr != MemError() || NULL == *handle ) + { + setStatus(STATUS_ERROR); + return; + } + + BlockMove( url_string, *handle, ( Size )( url.length() + 1 ) ); + + OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType ); + DisposeHandle( handle ); + if ( noErr != err ) + { + setStatus(STATUS_ERROR); + return; + }; + + mNavigateURL = url; + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); + message.setValue("uri", mNavigateURL); + sendMessage(message); + + // do pre-roll actions (typically fired for streaming movies but not always) + PrePrerollMovie( mMovieHandle, 0, getPlayRate(), moviePrePrerollCompleteCallback, ( void * )this ); + + Rect movie_rect = rectFromSize(mWidth, mHeight); + + // make a new movie controller + mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie ); + + // movie controller + MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this ); + + SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize ); + + // function that gets called when a frame is drawn + SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this ); + + setStatus(STATUS_LOADED); + + sizeChanged(); + }; + + bool unload() + { + // new movie and have to get title again + mReceivedTitle = false; + + if ( mMovieHandle ) + { + StopMovie( mMovieHandle ); + if ( mMovieController ) + { + MCMovieChanged( mMovieController, mMovieHandle ); + }; + }; + + if ( mMovieController ) + { + MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this ); + DisposeMovieController( mMovieController ); + mMovieController = NULL; + }; + + if ( mMovieHandle ) + { + SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this ); + DisposeMovie( mMovieHandle ); + mMovieHandle = NULL; + }; + + if ( mGWorldHandle ) + { + DisposeGWorld( mGWorldHandle ); + mGWorldHandle = NULL; + }; + + setStatus(STATUS_NONE); + + return true; + } + + bool navigateTo( const std::string url ) + { + unload(); + load( url ); + + return true; + }; + + bool sizeChanged() + { + if ( ! mMovieHandle ) + return false; + + // Check to see whether the movie's natural size has updated + { + int width, height; + getMovieNaturalSize(&width, &height); + if((width != 0) && (height != 0) && ((width != mNaturalWidth) || (height != mNaturalHeight))) + { + mNaturalWidth = width; + mNaturalHeight = height; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); + message.setValue("name", mTextureSegmentName); + message.setValueS32("width", width); + message.setValueS32("height", height); + sendMessage(message); + //std::cerr << "<--- Sending size change request to application with name: " << mTextureSegmentName << " - size is " << width << " x " << height << std::endl; + } + } + + // sanitize destination size + Rect dest_rect = rectFromSize(mWidth, mHeight); + + // media depth won't change + int depth_bits = mDepth * 8; + long rowbytes = mDepth * mTextureWidth; + + GWorldPtr old_gworld_handle = mGWorldHandle; + + if(mPixels != NULL) + { + // We have pixels. Set up a GWorld pointing at the texture. + OSErr result = NewGWorldFromPtr( &mGWorldHandle, depth_bits, &dest_rect, NULL, NULL, 0, (Ptr)mPixels, rowbytes); + if ( noErr != result ) + { + // TODO: unrecoverable?? throw exception? return something? + return false; + } + } + else + { + // We don't have pixels. Create a fake GWorld we can point the movie at when it's not safe to render normally. + Rect tempRect = rectFromSize(1, 1); + OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &tempRect, NULL, NULL, 0); + if ( noErr != result ) + { + // TODO: unrecoverable?? throw exception? return something? + return false; + } + } + + SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice( mGWorldHandle ) ); + + // If the GWorld was already set up, delete it. + if(old_gworld_handle != NULL) + { + DisposeGWorld( old_gworld_handle ); + } + + // Set up the movie display matrix + { + // scale movie to fit rect and invert vertically to match opengl image format + MatrixRecord transform; + SetIdentityMatrix( &transform ); // transforms are additive so start from identify matrix + double scaleX = (double) mWidth / mNaturalWidth; + double scaleY = -1.0 * (double) mHeight / mNaturalHeight; + double centerX = mWidth / 2.0; + double centerY = mHeight / 2.0; + ScaleMatrix( &transform, X2Fix( scaleX ), X2Fix( scaleY ), X2Fix( centerX ), X2Fix( centerY ) ); + SetMovieMatrix( mMovieHandle, &transform ); + } + + // update movie controller + if ( mMovieController ) + { + MCSetControllerPort( mMovieController, mGWorldHandle ); + MCPositionController( mMovieController, &dest_rect, &dest_rect, + mcTopLeftMovie | mcPositionDontInvalidate ); + MCMovieChanged( mMovieController, mMovieHandle ); + } + + + // Emit event with size change so the calling app knows about it too + // TODO: + //LLMediaEvent event( this ); + //mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); + + return true; + } + static Boolean mcActionFilterCallBack( MovieController mc, short action, void *params, long ref ) + { + Boolean result = false; + + MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; + + switch( action ) + { + // handle window resizing + case mcActionControllerSizeChanged: + // Ensure that the movie draws correctly at the new size + self->sizeChanged(); + break; + + // Block any movie controller actions that open URLs. + case mcActionLinkToURL: + case mcActionGetNextURL: + case mcActionLinkToURLExtended: + // Prevent the movie controller from handling the message + result = true; + break; + + default: + break; + }; + + return result; + }; + + static OSErr movieDrawingCompleteCallback( Movie call_back_movie, long ref ) + { + MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; + + // IMPORTANT: typically, a consumer who is observing this event will set a flag + // when this event is fired then render later. Be aware that the media stream + // can change during this period - dimensions, depth, format etc. + //LLMediaEvent event( self ); +// self->updateQuickTime(); + // TODO ^^^ + + + if ( self->mWidth > 0 && self->mHeight > 0 ) + self->setDirty( 0, 0, self->mWidth, self->mHeight ); + + return noErr; + }; + + static void moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref ) + { + MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; + + // TODO: + //LLMediaEvent event( self ); + //self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event ); + + // Send a "navigate complete" event. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); + message.setValue("uri", self->mNavigateURL); + message.setValueS32("result_code", 200); + message.setValue("result_string", "OK"); + self->sendMessage(message); + }; + + + void rewind() + { + GoToBeginningOfMovie( mMovieHandle ); + MCMovieChanged( mMovieController, mMovieHandle ); + }; + + bool processState() + { + if ( mCommand == COMMAND_PLAY ) + { + if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING || mStatus == STATUS_DONE ) + { + long state = GetMovieLoadState( mMovieHandle ); + + if ( state >= kMovieLoadStatePlaythroughOK ) + { + // if the movie is at the end (generally because it reached it naturally) + // and we play is requested, jump back to the start of the movie. + // note: this is different from having loop flag set. + if ( IsMovieDone( mMovieHandle ) ) + { + Fixed rate = X2Fix( 0.0 ); + MCDoAction( mMovieController, mcActionPlay, (void*)rate ); + rewind(); + }; + + MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() ); + MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); + setStatus(STATUS_PLAYING); + mCommand = COMMAND_NONE; + }; + }; + } + else + if ( mCommand == COMMAND_STOP ) + { + if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED || mStatus == STATUS_DONE ) + { + if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) + { + Fixed rate = X2Fix( 0.0 ); + MCDoAction( mMovieController, mcActionPlay, (void*)rate ); + rewind(); + + setStatus(STATUS_LOADED); + mCommand = COMMAND_NONE; + }; + }; + } + else + if ( mCommand == COMMAND_PAUSE ) + { + if ( mStatus == STATUS_PLAYING ) + { + if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) + { + Fixed rate = X2Fix( 0.0 ); + MCDoAction( mMovieController, mcActionPlay, (void*)rate ); + setStatus(STATUS_PAUSED); + mCommand = COMMAND_NONE; + }; + }; + }; + + return true; + }; + + void play(F64 rate) + { + mPlayRate = rate; + mCommand = COMMAND_PLAY; + }; + + void stop() + { + mCommand = COMMAND_STOP; + }; + + void pause() + { + mCommand = COMMAND_PAUSE; + }; + + void getMovieNaturalSize(int *movie_width, int *movie_height) + { + Rect rect; + + GetMovieNaturalBoundsRect( mMovieHandle, &rect ); + + int width = ( rect.right - rect.left ); + int height = ( rect.bottom - rect.top ); + + // make sure width and height fall in valid range + if ( width < mMinWidth ) + width = mMinWidth; + + if ( width > mMaxWidth ) + width = mMaxWidth; + + if ( height < mMinHeight ) + height = mMinHeight; + + if ( height > mMaxHeight ) + height = mMaxHeight; + + // return the new rect + *movie_width = width; + *movie_height = height; + } + + void updateQuickTime(int milliseconds) + { + if ( ! mMovieHandle ) + return; + + if ( ! mMovieController ) + return; + + // this wasn't required in 1.xx viewer but we have to manually + // work the Windows message pump now + #if defined( LL_WINDOWS ) + MSG msg; + while ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) + { + GetMessage( &msg, NULL, 0, 0 ); + TranslateMessage( &msg ); + DispatchMessage( &msg ); + }; + #endif + + MCIdle( mMovieController ); + + if ( ! mGWorldHandle ) + return; + + if ( mMediaSizeChanging ) + return; + + // update state machine + processState(); + + // see if title arrived and if so, update member variable with contents + checkTitle(); + + // QT call to see if we are at the end - can't do with controller + if ( IsMovieDone( mMovieHandle ) ) + { + // special code for looping - need to rewind at the end of the movie + if ( mIsLooping ) + { + // go back to start + rewind(); + + if ( mMovieController ) + { + // kick off new play + MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() ); + + // set the volume + MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); + }; + } + else + { + if(mStatus == STATUS_PLAYING) + { + setStatus(STATUS_DONE); + } + } + } + + }; + + int getDataWidth() const + { + if ( mGWorldHandle ) + { + int depth = mDepth; + + if (depth < 1) + depth = 1; + + // ALWAYS use the row bytes from the PixMap if we have a GWorld because + // sometimes it's not the same as mMediaDepth * mMediaWidth ! + PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle ); + return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth; + } + else + { + // TODO : return LLMediaImplCommon::getaDataWidth(); + return 0; + } + }; + + void seek( F64 time ) + { + if ( mMovieController ) + { + TimeRecord when; + when.scale = GetMovieTimeScale( mMovieHandle ); + when.base = 0; + + // 'time' is in (floating point) seconds. The timebase time will be in 'units', where + // there are 'scale' units per second. + SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) ); + + when.value.hi = ( SInt32 )( raw_time >> 32 ); + when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) ); + + MCDoAction( mMovieController, mcActionGoToTime, &when ); + }; + }; + + F64 getLoadedDuration() + { + TimeValue duration; + if(GetMaxLoadedTimeInMovie( mMovieHandle, &duration ) != noErr) + { + // If GetMaxLoadedTimeInMovie returns an error, return the full duration of the movie. + duration = GetMovieDuration( mMovieHandle ); + } + TimeValue scale = GetMovieTimeScale( mMovieHandle ); + + return (F64)duration / (F64)scale; + }; + + F64 getDuration() + { + TimeValue duration = GetMovieDuration( mMovieHandle ); + TimeValue scale = GetMovieTimeScale( mMovieHandle ); + + return (F64)duration / (F64)scale; + }; + + F64 getCurrentTime() + { + TimeValue curr_time = GetMovieTime( mMovieHandle, 0 ); + TimeValue scale = GetMovieTimeScale( mMovieHandle ); + + return (F64)curr_time / (F64)scale; + }; + + void setVolume( F64 volume ) + { + mCurVolume = (short)(volume * ( double ) 0x100 ); + + if ( mMovieController ) + { + MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void update(int milliseconds = 0) + { + updateQuickTime(milliseconds); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseDown( int x, int y ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseUp( int x, int y ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseMove( int x, int y ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyPress( unsigned char key ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // Grab movie title into mMovieTitle - should be called repeatedly + // until it returns true since movie title takes a while to become + // available. + const bool getMovieTitle() + { + // grab meta data from movie + QTMetaDataRef media_data_ref; + OSErr result = QTCopyMovieMetaData( mMovieHandle, &media_data_ref ); + if ( noErr != result ) + return false; + + // look up "Display Name" in meta data + OSType meta_data_key = kQTMetaDataCommonKeyDisplayName; + QTMetaDataItem item = kQTMetaDataItemUninitialized; + result = QTMetaDataGetNextItem( media_data_ref, kQTMetaDataStorageFormatWildcard, + 0, kQTMetaDataKeyFormatCommon, + (const UInt8 *)&meta_data_key, + sizeof( meta_data_key ), &item ); + if ( noErr != result ) + return false; + + // find the size of the title + ByteCount size; + result = QTMetaDataGetItemValue( media_data_ref, item, NULL, 0, &size ); + if ( noErr != result || size <= 0 /*|| size > 1024 FIXME: arbitrary limit */ ) + return false; + + // allocate some space and grab it + UInt8* item_data = new UInt8[ size + 1 ]; + memset( item_data, 0, ( size + 1 ) * sizeof( UInt8 ) ); + result = QTMetaDataGetItemValue( media_data_ref, item, item_data, size, NULL ); + if ( noErr != result ) + { + delete [] item_data; + return false; + }; + + // save it + if ( strlen( (char*)item_data ) ) + mMovieTitle = std::string( (char* )item_data ); + else + mMovieTitle = ""; + + // clean up + delete [] item_data; + + return true; + }; + + // called regularly to see if title changed + void checkTitle() + { + // we did already receive title so keep checking + if ( ! mReceivedTitle ) + { + // grab title from movie meta data + if ( getMovieTitle() ) + { + // pass back to host application + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); + message.setValue("name", mMovieTitle ); + sendMessage( message ); + + // stop looking once we find a title for this movie. + // TODO: this may to be reset if movie title changes + // during playback but this is okay for now + mReceivedTitle = true; + }; + }; + }; +}; + +MediaPluginQuickTime::MediaPluginQuickTime( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) : + MediaPluginBase(host_send_func, host_user_data), + mMinWidth( 0 ), + mMaxWidth( 2048 ), + mMinHeight( 0 ), + mMaxHeight( 2048 ) +{ +// std::cerr << "MediaPluginQuickTime constructor" << std::endl; + + mNaturalWidth = -1; + mNaturalHeight = -1; + mMovieHandle = 0; + mGWorldHandle = 0; + mMovieController = 0; + mCurVolume = 0x99; + mMediaSizeChanging = false; + mIsLooping = false; + mMovieTitle = std::string(); + mReceivedTitle = false; + mCommand = COMMAND_NONE; + mPlayRate = 0.0f; + mStatus = STATUS_NONE; +} + +MediaPluginQuickTime::~MediaPluginQuickTime() +{ +// std::cerr << "MediaPluginQuickTime destructor" << std::endl; + + ExitMovies(); + +#ifdef LL_WINDOWS + TerminateQTML(); +// std::cerr << "QuickTime closing down" << std::endl; +#endif +} + + +void MediaPluginQuickTime::receiveMessage(const char *message_string) +{ +// std::cerr << "MediaPluginQuickTime::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + // Normally a plugin would only specify one of these two subclasses, but this is a demo... + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; + message.setValueLLSD("versions", versions); + + #ifdef LL_WINDOWS + + // QuickTime 7.6.4 has an issue (that was not present in 7.6.2) with initializing QuickTime + // according to this article: http://lists.apple.com/archives/QuickTime-API/2009/Sep/msg00097.html + // The solution presented there appears to work. + QTLoadLibrary("qtcf.dll"); + + // main initialization for QuickTime - only required on Windows + OSErr result = InitializeQTML( 0L ); + if ( result != noErr ) + { + //TODO: If no QT on Windows, this fails - respond accordingly. + } + else + { + //std::cerr << "QuickTime initialized" << std::endl; + }; + #endif + + // required for both Windows and Mac + EnterMovies(); + + std::string plugin_version = "QuickTime media plugin, QuickTime version "; + + long version = 0; + Gestalt( gestaltQuickTimeVersion, &version ); + std::ostringstream codec( "" ); + codec << std::hex << version << std::dec; + plugin_version += codec.str(); + message.setValue("plugin_version", plugin_version); + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + F64 time = message_in.getValueReal("time"); + + // Convert time to milliseconds for update() + update((int)(time * 1000.0f)); + } + else if(message_name == "cleanup") + { + // TODO: clean up here + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); +// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory added, name: " << name +// << ", size: " << info.mSize +// << ", address: " << info.mAddress +// << std::endl; + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + +// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory remove, name = " << name << std::endl; + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + + // Make sure the movie GWorld is no longer pointed at the shared segment. + sizeChanged(); + } + mSharedSegments.erase(iter); + } + else + { +// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown shared memory region!" << std::endl; + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { +// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "init") + { + // This is the media init message -- all necessary data for initialization should have been received. + + // Plugin gets to decide the texture parameters to use. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + #if defined(LL_WINDOWS) + // Values for Windows + mDepth = 3; + message.setValueU32("format", GL_RGB); + message.setValueU32("type", GL_UNSIGNED_BYTE); + + // We really want to pad the texture width to a multiple of 32 bytes, but since we're using 3-byte pixels, it doesn't come out even. + // Padding to a multiple of 3*32 guarantees it'll divide out properly. + message.setValueU32("padding", 32 * 3); + #else + // Values for Mac + mDepth = 4; + message.setValueU32("format", GL_BGRA_EXT); + #ifdef __BIG_ENDIAN__ + message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV ); + #else + message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8); + #endif + + // Pad texture width to a multiple of 32 bytes, to line up with cache lines. + message.setValueU32("padding", 32); + #endif + message.setValueS32("depth", mDepth); + message.setValueU32("internalformat", GL_RGB); + message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. + message.setValueBoolean("allow_downsample", true); + sendMessage(message); + } + else if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + //std::cerr << "---->Got size change instruction from application with name: " << name << " - size is " << width << " x " << height << std::endl; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { +// std::cerr << "%%% Got size change, new size is " << width << " by " << height << std::endl; +// std::cerr << "%%%% texture size is " << texture_width << " by " << texture_height << std::endl; + + mPixels = (unsigned char*)iter->second.mAddress; + mTextureSegmentName = name; + mWidth = width; + mHeight = height; + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + mMediaSizeChanging = false; + + sizeChanged(); + + update(); + }; + }; + } + else if(message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + load( uri ); + sendStatus(); + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + + if(event == "down") + { + mouseDown(x, y); + } + else if(event == "up") + { + mouseUp(x, y); + } + else if(event == "move") + { + mouseMove(x, y); + }; + }; + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if(message_name == "stop") + { + stop(); + } + else if(message_name == "start") + { + F64 rate = 0.0; + if(message_in.hasValue("rate")) + { + rate = message_in.getValueReal("rate"); + } + play(rate); + } + else if(message_name == "pause") + { + pause(); + } + else if(message_name == "seek") + { + F64 time = message_in.getValueReal("time"); + seek(time); + } + else if(message_name == "set_loop") + { + bool loop = message_in.getValueBoolean("loop"); + mIsLooping = loop; + } + else if(message_name == "set_volume") + { + F64 volume = message_in.getValueReal("volume"); + setVolume(volume); + } + } + else + { +// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown message class: " << message_class << std::endl; + }; + }; +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + MediaPluginQuickTime *self = new MediaPluginQuickTime(host_send_func, host_user_data); + *plugin_send_func = MediaPluginQuickTime::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} + +#else // LL_QUICKTIME_ENABLED + +// Stubbed-out class with constructor/destructor (necessary or windows linker +// will just think its dead code and optimize it all out) +class MediaPluginQuickTime : public MediaPluginBase +{ +public: + MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginQuickTime(); + /* virtual */ void receiveMessage(const char *message_string); +}; + +MediaPluginQuickTime::MediaPluginQuickTime( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) : + MediaPluginBase(host_send_func, host_user_data) +{ + // no-op +} + +MediaPluginQuickTime::~MediaPluginQuickTime() +{ + // no-op +} + +void MediaPluginQuickTime::receiveMessage(const char *message_string) +{ + // no-op +} + +// We're building without quicktime enabled. Just refuse to initialize. +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + return -1; +} + +#endif // LL_QUICKTIME_ENABLED diff --git a/linden/indra/media_plugins/webkit/CMakeLists.txt b/linden/indra/media_plugins/webkit/CMakeLists.txt new file mode 100644 index 000000000..303a77437 --- /dev/null +++ b/linden/indra/media_plugins/webkit/CMakeLists.txt @@ -0,0 +1,121 @@ +# -*- cmake -*- + +project(media_plugin_webkit) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(UI) +include(Linking) +include(PluginAPI) +include(MediaPluginBase) +include(FindOpenGL) +include(PulseAudio) + +include(WebKitLibPlugin) + +include_directories( + ${PULSEAUDIO_INCLUDE_DIRS} + ${LLPLUGIN_INCLUDE_DIRS} + ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} + ${LLQTWEBKIT_INCLUDE_DIR} +) + +### media_plugin_webkit + +set(media_plugin_webkit_SOURCE_FILES + media_plugin_webkit.cpp + ) + +set(media_plugin_webkit_HEADER_FILES + volume_catcher.h + ) + +set(media_plugin_webkit_LINK_LIBRARIES + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${WEBKIT_PLUGIN_LIBRARIES} + ${PLUGIN_API_WINDOWS_LIBRARIES} + ${PULSEAUDIO_LIBRARIES} +) + +# Select which VolumeCatcher implementation to use +if (LINUX) + if (PULSEAUDIO) + list(APPEND media_plugin_webkit_SOURCE_FILES linux_volume_catcher.cpp) + endif (PULSEAUDIO) + list(APPEND media_plugin_webkit_LINK_LIBRARIES + ${UI_LIBRARIES} # for glib/GTK + ) +elseif (DARWIN) + list(APPEND media_plugin_webkit_SOURCE_FILES mac_volume_catcher.cpp) + find_library(CORESERVICES_LIBRARY CoreServices) + find_library(AUDIOUNIT_LIBRARY AudioUnit) + list(APPEND media_plugin_webkit_LINK_LIBRARIES + ${CORESERVICES_LIBRARY} # for Component Manager calls + ${AUDIOUNIT_LIBRARY} # for AudioUnit calls + ) +elseif (WINDOWS) + list(APPEND media_plugin_webkit_SOURCE_FILES windows_volume_catcher.cpp) +else (LINUX) + # All other platforms use the dummy volume catcher for now. + list(APPEND media_plugin_webkit_SOURCE_FILES dummy_volume_catcher.cpp) +endif (LINUX) + +set_source_files_properties(${media_plugin_webkit_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND media_plugin_webkit_SOURCE_FILES ${media_plugin_webkit_HEADER_FILES}) + +add_library(media_plugin_webkit + SHARED + ${media_plugin_webkit_SOURCE_FILES} +) + +target_link_libraries(media_plugin_webkit ${media_plugin_webkit_LINK_LIBRARIES}) + +add_dependencies(media_plugin_webkit + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + +if (WINDOWS) + set_target_properties( + media_plugin_webkit + PROPERTIES + LINK_FLAGS "/MANIFEST:NO" + ) +endif (WINDOWS) + +if (DARWIN) + # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name + set_target_properties( + media_plugin_webkit + PROPERTIES + PREFIX "" + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" + ) + + # copy the webkit dylib to the build directory + add_custom_command( + TARGET media_plugin_webkit POST_BUILD +# OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/libllqtwebkit.dylib + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/ + DEPENDS media_plugin_webkit ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib + ) + +endif (DARWIN) + diff --git a/linden/indra/media_plugins/webkit/dummy_volume_catcher.cpp b/linden/indra/media_plugins/webkit/dummy_volume_catcher.cpp new file mode 100644 index 000000000..4df988789 --- /dev/null +++ b/linden/indra/media_plugins/webkit/dummy_volume_catcher.cpp @@ -0,0 +1,65 @@ +/** + * @file dummy_volume_catcher.cpp + * @brief A null implementation of the "VolumeCatcher" class for platforms where it's not implemented yet. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "volume_catcher.h" + + +class VolumeCatcherImpl +{ +}; + +///////////////////////////////////////////////////// + +VolumeCatcher::VolumeCatcher() +{ + pimpl = NULL; +} + +VolumeCatcher::~VolumeCatcher() +{ +} + +void VolumeCatcher::setVolume(F32 volume) +{ +} + +void VolumeCatcher::setPan(F32 pan) +{ +} + +void VolumeCatcher::pump() +{ +} + diff --git a/linden/indra/media_plugins/webkit/linux_volume_catcher.cpp b/linden/indra/media_plugins/webkit/linux_volume_catcher.cpp new file mode 100644 index 000000000..cc3836ea5 --- /dev/null +++ b/linden/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -0,0 +1,473 @@ +/** + * @file linux_volume_catcher.cpp + * @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +/* + The high-level design is as follows: + 1) Connect to the PulseAudio daemon + 2) Watch for the creation of new audio players connecting to the daemon (this includes ALSA clients running on the PulseAudio emulation layer, such as Flash plugins) + 3) Examine any new audio player's PID to see if it belongs to our own process + 4) If so, tell PA to adjust the volume of that audio player ('sink input' in PA parlance) + 5) Keep a list of all living audio players that we care about, adjust the volumes of all of them when we get a new setVolume() call + */ + +# include <set> //imprudence + +#include "linden_common.h" + +#include "volume_catcher.h" + + +extern "C" { +#include <glib.h> +#include <glib-object.h> + +#include <pulse/introspect.h> +#include <pulse/context.h> +#include <pulse/subscribe.h> +#include <pulse/glib-mainloop.h> // There's no special reason why we want the *glib* PA mainloop, but the generic polling implementation seems broken. + +#include "aiaprpool.h" +#include "apr_dso.h" +} + +//////////////////////////////////////////////////// + +#define DEBUGMSG(...) do {} while(0) +#define INFOMSG(...) do {} while(0) +#define WARNMSG(...) do {} while(0) + +#define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) RTN (*ll##PASYM)(__VA_ARGS__) = NULL +#include "linux_volume_catcher_pa_syms.inc" +#include "linux_volume_catcher_paglib_syms.inc" +#undef LL_PA_SYM + +static bool sSymsGrabbed = false; +static AIAPRPool sSymPADSOMemoryPool; +static apr_dso_handle_t *sSymPADSOHandleG = NULL; + +bool grab_pa_syms(std::string pulse_dso_name) +{ + if (sSymsGrabbed) + { + // already have grabbed good syms + return true; + } + + bool sym_error = false; + bool rtn = false; + apr_status_t rv; + apr_dso_handle_t *sSymPADSOHandle = NULL; + +#define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##PASYM, sSymPADSOHandle, #PASYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #PASYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #PASYM, (void*)ll##PASYM);}while(0) + + //attempt to load the shared library + sSymPADSOMemoryPool.create(); + + if ( APR_SUCCESS == (rv = apr_dso_load(&sSymPADSOHandle, + pulse_dso_name.c_str(), + sSymPADSOMemoryPool()) )) + { + INFOMSG("Found DSO: %s", pulse_dso_name.c_str()); + +#include "linux_volume_catcher_pa_syms.inc" +#include "linux_volume_catcher_paglib_syms.inc" + + if ( sSymPADSOHandle ) + { + sSymPADSOHandleG = sSymPADSOHandle; + sSymPADSOHandle = NULL; + } + + rtn = !sym_error; + } + else + { + INFOMSG("Couldn't load DSO: %s", pulse_dso_name.c_str()); + rtn = false; // failure + } + + if (sym_error) + { + WARNMSG("Failed to find necessary symbols in PulseAudio libraries."); + } +#undef LL_PA_SYM + + sSymsGrabbed = rtn; + return rtn; +} + + +void ungrab_pa_syms() +{ + // should be safe to call regardless of whether we've + // actually grabbed syms. + + if ( sSymPADSOHandleG ) + { + apr_dso_unload(sSymPADSOHandleG); + sSymPADSOHandleG = NULL; + } + + sSymPADSOMemoryPool.destroy(); + + // NULL-out all of the symbols we'd grabbed +#define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{ll##PASYM = NULL;}while(0) +#include "linux_volume_catcher_pa_syms.inc" +#include "linux_volume_catcher_paglib_syms.inc" +#undef LL_PA_SYM + + sSymsGrabbed = false; +} +//////////////////////////////////////////////////// + +// PulseAudio requires a chain of callbacks with C linkage +extern "C" { + void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata); + void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata); + void callback_context_state(pa_context *context, void *userdata); +} + + +class VolumeCatcherImpl +{ +public: + VolumeCatcherImpl(); + ~VolumeCatcherImpl(); + + void setVolume(F32 volume); + void pump(void); + + // for internal use - can't be private because used from our C callbacks + + bool loadsyms(std::string pulse_dso_name); + void init(); + void cleanup(); + + void update_all_volumes(F32 volume); + void update_index_volume(U32 index, F32 volume); + void connected_okay(); + + std::set<U32> mSinkInputIndices; + std::map<U32,U32> mSinkInputNumChannels; + F32 mDesiredVolume; + pa_glib_mainloop *mMainloop; + pa_context *mPAContext; + bool mConnected; + bool mGotSyms; +}; + +VolumeCatcherImpl::VolumeCatcherImpl() + : mDesiredVolume(0.0f), + mMainloop(NULL), + mPAContext(NULL), + mConnected(false), + mGotSyms(false) +{ + init(); +} + +VolumeCatcherImpl::~VolumeCatcherImpl() +{ + cleanup(); +} + +bool VolumeCatcherImpl::loadsyms(std::string pulse_dso_name) +{ + return grab_pa_syms(pulse_dso_name); +} + +void VolumeCatcherImpl::init() +{ + // try to be as defensive as possible because PA's interface is a + // bit fragile and (for our purposes) we'd rather simply not function + // than crash + + // we cheat and rely upon libpulse-mainloop-glib.so.0 to pull-in + // libpulse.so.0 - this isn't a great assumption, and the two DSOs should + // probably be loaded separately. Our Linux DSO framework needs refactoring, + // we do this sort of thing a lot with practically identical logic... + mGotSyms = loadsyms("libpulse-mainloop-glib.so.0"); + if (!mGotSyms) return; + + // better make double-sure glib itself is initialized properly. + if (!g_thread_supported ()) g_thread_init (NULL); + g_type_init(); + + mMainloop = llpa_glib_mainloop_new(g_main_context_default()); + if (mMainloop) + { + pa_mainloop_api *api = llpa_glib_mainloop_get_api(mMainloop); + if (api) + { + pa_proplist *proplist = llpa_proplist_new(); + if (proplist) + { + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-player"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.secondlife.viewer.mediaplugvoladjust"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "SL Plugin Volume Adjuster"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, "1"); + + // plain old pa_context_new() is broken! + mPAContext = llpa_context_new_with_proplist(api, NULL, proplist); + llpa_proplist_free(proplist); + } + } + } + + // Now we've set up a PA context and mainloop, try connecting the + // PA context to a PA daemon. + if (mPAContext) + { + llpa_context_set_state_callback(mPAContext, callback_context_state, this); + pa_context_flags_t cflags = (pa_context_flags)0; // maybe add PA_CONTEXT_NOAUTOSPAWN? + if (llpa_context_connect(mPAContext, NULL, cflags, NULL) >= 0) + { + // Okay! We haven't definitely connected, but we + // haven't definitely failed yet. + } + else + { + // Failed to connect to PA manager... we'll leave + // things like that. Perhaps we should try again later. + } + } +} + +void VolumeCatcherImpl::cleanup() +{ + mConnected = false; + + if (mGotSyms && mPAContext) + { + llpa_context_disconnect(mPAContext); + llpa_context_unref(mPAContext); + } + mPAContext = NULL; + + if (mGotSyms && mMainloop) + { + llpa_glib_mainloop_free(mMainloop); + } + mMainloop = NULL; +} + +void VolumeCatcherImpl::setVolume(F32 volume) +{ + mDesiredVolume = volume; + + if (!mGotSyms) return; + + if (mConnected && mPAContext) + { + update_all_volumes(mDesiredVolume); + } + + pump(); +} + +void VolumeCatcherImpl::pump() +{ + gboolean may_block = FALSE; + g_main_context_iteration(g_main_context_default(), may_block); +} + +void VolumeCatcherImpl::connected_okay() +{ + pa_operation *op; + + // fetch global list of existing sinkinputs + if ((op = llpa_context_get_sink_input_info_list(mPAContext, + callback_discovered_sinkinput, + this))) + { + llpa_operation_unref(op); + } + + // subscribe to future global sinkinput changes + llpa_context_set_subscribe_callback(mPAContext, + callback_subscription_alert, + this); + if ((op = llpa_context_subscribe(mPAContext, (pa_subscription_mask_t) + (PA_SUBSCRIPTION_MASK_SINK_INPUT), + NULL, NULL))) + { + llpa_operation_unref(op); + } +} + +void VolumeCatcherImpl::update_all_volumes(F32 volume) +{ + for (std::set<U32>::iterator it = mSinkInputIndices.begin(); + it != mSinkInputIndices.end(); ++it) + { + update_index_volume(*it, volume); + } +} + +void VolumeCatcherImpl::update_index_volume(U32 index, F32 volume) +{ + static pa_cvolume cvol; + llpa_cvolume_set(&cvol, mSinkInputNumChannels[index], + llpa_sw_volume_from_linear(volume)); + + pa_context *c = mPAContext; + uint32_t idx = index; + const pa_cvolume *cvolumep = &cvol; + pa_context_success_cb_t cb = NULL; // okay as null + void *userdata = NULL; // okay as null + + pa_operation *op; + if ((op = llpa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata))) + { + llpa_operation_unref(op); + } +} + + +void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata) +{ + VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)userdata); + llassert(impl); + + if (0 == eol) + { + pa_proplist *proplist = sii->proplist; + pid_t sinkpid = atoll(llpa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID)); + + if (sinkpid == getpid()) // does the discovered sinkinput belong to this process? + { + bool is_new = (impl->mSinkInputIndices.find(sii->index) == + impl->mSinkInputIndices.end()); + + impl->mSinkInputIndices.insert(sii->index); + impl->mSinkInputNumChannels[sii->index] = sii->channel_map.channels; + + if (is_new) + { + // new! + impl->update_index_volume(sii->index, impl->mDesiredVolume); + } + else + { + // seen it already, do nothing. + } + } + } +} + +void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata) +{ + VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)userdata); + llassert(impl); + + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == + PA_SUBSCRIPTION_EVENT_REMOVE) + { + // forget this sinkinput, if we were caring about it + impl->mSinkInputIndices.erase(index); + impl->mSinkInputNumChannels.erase(index); + } + else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == + PA_SUBSCRIPTION_EVENT_NEW) + { + // ask for more info about this new sinkinput + pa_operation *op; + if ((op = llpa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl))) + { + llpa_operation_unref(op); + } + } + else + { + // property change on this sinkinput - we don't care. + } + break; + + default:; + } +} + +void callback_context_state(pa_context *context, void *userdata) +{ + VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)userdata); + llassert(impl); + + switch (llpa_context_get_state(context)) + { + case PA_CONTEXT_READY: + impl->mConnected = true; + impl->connected_okay(); + break; + case PA_CONTEXT_TERMINATED: + impl->mConnected = false; + break; + case PA_CONTEXT_FAILED: + impl->mConnected = false; + break; + default:; + } +} + +///////////////////////////////////////////////////// + +VolumeCatcher::VolumeCatcher() +{ + pimpl = new VolumeCatcherImpl(); +} + +VolumeCatcher::~VolumeCatcher() +{ + delete pimpl; + pimpl = NULL; +} + +void VolumeCatcher::setVolume(F32 volume) +{ + llassert(pimpl); + pimpl->setVolume(volume); +} + +void VolumeCatcher::setPan(F32 pan) +{ + // TODO: implement this (if possible) +} + +void VolumeCatcher::pump() +{ + llassert(pimpl); + pimpl->pump(); +} diff --git a/linden/indra/media_plugins/webkit/linux_volume_catcher.h b/linden/indra/media_plugins/webkit/linux_volume_catcher.h new file mode 100755 index 000000000..d4a1b38f9 --- /dev/null +++ b/linden/indra/media_plugins/webkit/linux_volume_catcher.h @@ -0,0 +1,56 @@ +/** + * @file linux_volume_catcher.h + * @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LINUX_VOLUME_CATCHER_H +#define LINUX_VOLUME_CATCHER_H + +#include "linden_common.h" + +class LinuxVolumeCatcherImpl; + +class LinuxVolumeCatcher +{ + public: + LinuxVolumeCatcher(); + ~LinuxVolumeCatcher(); + + void setVolume(F32 volume); // 0.0 - 1.0 + void pump(); // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume + + private: + LinuxVolumeCatcherImpl *pimpl; +}; + +#endif // LINUX_VOLUME_CATCHER_H diff --git a/linden/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc b/linden/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc new file mode 100644 index 000000000..d806b4842 --- /dev/null +++ b/linden/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc @@ -0,0 +1,21 @@ +// required symbols to grab +LL_PA_SYM(true, pa_context_connect, int, pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api); +LL_PA_SYM(true, pa_context_disconnect, void, pa_context *c); +LL_PA_SYM(true, pa_context_get_sink_input_info, pa_operation*, pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_get_sink_input_info_list, pa_operation*, pa_context *c, pa_sink_input_info_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_get_state, pa_context_state_t, pa_context *c); +LL_PA_SYM(true, pa_context_new_with_proplist, pa_context*, pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist); +LL_PA_SYM(true, pa_context_set_sink_input_volume, pa_operation*, pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_set_state_callback, void, pa_context *c, pa_context_notify_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_set_subscribe_callback, void, pa_context *c, pa_context_subscribe_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_subscribe, pa_operation*, pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_unref, void, pa_context *c); +LL_PA_SYM(true, pa_cvolume_set, pa_cvolume*, pa_cvolume *a, unsigned channels, pa_volume_t v); +LL_PA_SYM(true, pa_operation_unref, void, pa_operation *o); +LL_PA_SYM(true, pa_proplist_free, void, pa_proplist* p); +LL_PA_SYM(true, pa_proplist_gets, const char*, pa_proplist *p, const char *key); +LL_PA_SYM(true, pa_proplist_new, pa_proplist*, void); +LL_PA_SYM(true, pa_proplist_sets, int, pa_proplist *p, const char *key, const char *value); +LL_PA_SYM(true, pa_sw_volume_from_linear, pa_volume_t, double v); + +// optional symbols to grab diff --git a/linden/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc b/linden/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc new file mode 100644 index 000000000..abf628c96 --- /dev/null +++ b/linden/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc @@ -0,0 +1,6 @@ +// required symbols to grab +LL_PA_SYM(true, pa_glib_mainloop_free, void, pa_glib_mainloop* g); +LL_PA_SYM(true, pa_glib_mainloop_get_api, pa_mainloop_api*, pa_glib_mainloop* g); +LL_PA_SYM(true, pa_glib_mainloop_new, pa_glib_mainloop *, GMainContext *c); + +// optional symbols to grab diff --git a/linden/indra/media_plugins/webkit/mac_volume_catcher.cpp b/linden/indra/media_plugins/webkit/mac_volume_catcher.cpp new file mode 100644 index 000000000..190823f73 --- /dev/null +++ b/linden/indra/media_plugins/webkit/mac_volume_catcher.cpp @@ -0,0 +1,275 @@ +/** + * @file mac_volume_catcher.cpp + * @brief A Mac OS X specific hack to control the volume level of all audio channels opened by a process. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +/************************************************************************************************************** + This code works by using CaptureComponent to capture the "Default Output" audio component + (kAudioUnitType_Output/kAudioUnitSubType_DefaultOutput) and delegating all calls to the original component. + It does this just to keep track of all instances of the default output component, so that it can set the + kHALOutputParam_Volume parameter on all of them to adjust the output volume. +**************************************************************************************************************/ + +#include "volume_catcher.h" + +#include <Carbon/Carbon.h> +#include <QuickTime/QuickTime.h> +#include <AudioUnit/AudioUnit.h> + +struct VolumeCatcherStorage; + +class VolumeCatcherImpl +{ +public: + + void setVolume(F32 volume); + void setPan(F32 pan); + + void setInstanceVolume(VolumeCatcherStorage *instance); + + std::list<VolumeCatcherStorage*> mComponentInstances; + Component mOriginalDefaultOutput; + Component mVolumeAdjuster; + + static VolumeCatcherImpl *getInstance(); +private: + // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance. + VolumeCatcherImpl(); + static VolumeCatcherImpl *sInstance; + + // The singlar instance of this class is expected to last until the process exits. + // To ensure this, we declare the destructor here but never define it, so any code which attempts to destroy the instance will not link. + ~VolumeCatcherImpl(); + + F32 mVolume; + F32 mPan; +}; + +VolumeCatcherImpl *VolumeCatcherImpl::sInstance = NULL;; + +struct VolumeCatcherStorage +{ + ComponentInstance self; + ComponentInstance delegate; +}; + +static ComponentResult volume_catcher_component_entry(ComponentParameters *cp, Handle componentStorage); +static ComponentResult volume_catcher_component_open(VolumeCatcherStorage *storage, ComponentInstance self); +static ComponentResult volume_catcher_component_close(VolumeCatcherStorage *storage, ComponentInstance self); + +VolumeCatcherImpl *VolumeCatcherImpl::getInstance() +{ + if(!sInstance) + { + sInstance = new VolumeCatcherImpl; + } + + return sInstance; +} + +VolumeCatcherImpl::VolumeCatcherImpl() +{ + mVolume = 1.0; // default to full volume + mPan = 0.0; // and center pan + + ComponentDescription desc; + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_DefaultOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + // Find the original default output component + mOriginalDefaultOutput = FindNextComponent(NULL, &desc); + + // Register our own output component with the same parameters + mVolumeAdjuster = RegisterComponent(&desc, NewComponentRoutineUPP(volume_catcher_component_entry), 0, NULL, NULL, NULL); + + // Capture the original component, so we always get found instead. + CaptureComponent(mOriginalDefaultOutput, mVolumeAdjuster); + +} + +static ComponentResult volume_catcher_component_entry(ComponentParameters *cp, Handle componentStorage) +{ + ComponentResult result = badComponentSelector; + VolumeCatcherStorage *storage = (VolumeCatcherStorage*)componentStorage; + + switch(cp->what) + { + case kComponentOpenSelect: +// std::cerr << "kComponentOpenSelect" << std::endl; + result = CallComponentFunctionWithStorageProcInfo((Handle)storage, cp, (ProcPtr)volume_catcher_component_open, uppCallComponentOpenProcInfo); + break; + + case kComponentCloseSelect: +// std::cerr << "kComponentCloseSelect" << std::endl; + result = CallComponentFunctionWithStorageProcInfo((Handle)storage, cp, (ProcPtr)volume_catcher_component_close, uppCallComponentCloseProcInfo); + // CallComponentFunctionWithStorageProcInfo + break; + + default: +// std::cerr << "Delegating selector: " << cp->what << " to component instance " << storage->delegate << std::endl; + result = DelegateComponentCall(cp, storage->delegate); + break; + } + + return result; +} + +static ComponentResult volume_catcher_component_open(VolumeCatcherStorage *storage, ComponentInstance self) +{ + ComponentResult result = noErr; + VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); + + storage = new VolumeCatcherStorage; + + storage->self = self; + storage->delegate = NULL; + + result = OpenAComponent(impl->mOriginalDefaultOutput, &(storage->delegate)); + + if(result != noErr) + { +// std::cerr << "OpenAComponent result = " << result << ", component ref = " << storage->delegate << std::endl; + + // If we failed to open the delagate component, our open is going to fail. Clean things up. + delete storage; + } + else + { + // Success -- set up this component's storage + SetComponentInstanceStorage(self, (Handle)storage); + + // add this instance to the global list + impl->mComponentInstances.push_back(storage); + + // and set up the initial volume + impl->setInstanceVolume(storage); + } + + return result; +} + +static ComponentResult volume_catcher_component_close(VolumeCatcherStorage *storage, ComponentInstance self) +{ + ComponentResult result = noErr; + + if(storage) + { + if(storage->delegate) + { + CloseComponent(storage->delegate); + storage->delegate = NULL; + } + + VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); + impl->mComponentInstances.remove(storage); + delete[] storage; + } + + return result; +} + +void VolumeCatcherImpl::setVolume(F32 volume) +{ + VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); + impl->mVolume = volume; + + // Iterate through all known instances, setting the volume on each. + for(std::list<VolumeCatcherStorage*>::iterator iter = mComponentInstances.begin(); iter != mComponentInstances.end(); ++iter) + { + impl->setInstanceVolume(*iter); + } +} + +void VolumeCatcherImpl::setPan(F32 pan) +{ + VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); + impl->mPan = pan; + + // TODO: implement this. + // This will probably require adding a "panner" audio unit to the chain somehow. + // There's also a "3d mixer" component that we might be able to use... +} + +void VolumeCatcherImpl::setInstanceVolume(VolumeCatcherStorage *instance) +{ +// std::cerr << "Setting volume on component instance: " << (instance->delegate) << " to " << mVolume << std::endl; + + OSStatus err = noErr; + + if(instance && instance->delegate) + { + err = AudioUnitSetParameter( + instance->delegate, + kHALOutputParam_Volume, + kAudioUnitScope_Global, + 0, + mVolume, + 0); + } + + if(err) + { +// std::cerr << " AudioUnitSetParameter returned " << err << std::endl; + } +} + +///////////////////////////////////////////////////// + +VolumeCatcher::VolumeCatcher() +{ + pimpl = VolumeCatcherImpl::getInstance(); +} + +VolumeCatcher::~VolumeCatcher() +{ + // Let the instance persist until exit. +} + +void VolumeCatcher::setVolume(F32 volume) +{ + pimpl->setVolume(volume); +} + +void VolumeCatcher::setPan(F32 pan) +{ + pimpl->setPan(pan); +} + +void VolumeCatcher::pump() +{ + // No periodic tasks are necessary for this implementation. +} + diff --git a/linden/indra/media_plugins/webkit/media_plugin_webkit.cpp b/linden/indra/media_plugins/webkit/media_plugin_webkit.cpp new file mode 100755 index 000000000..4a0055792 --- /dev/null +++ b/linden/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -0,0 +1,1209 @@ +/** + * @file media_plugin_webkit.cpp + * @brief Webkit plugin for LLMedia API plugin system + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "llqtwebkit.h" + +#include "linden_common.h" +#include "indra_constants.h" // for indra keyboard codes + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" +#include <iomanip> + +// set to 1 if you're using the version of llqtwebkit that's QPixmap-ified +#if LL_LINUX +# define LL_QTWEBKIT_USES_PIXMAPS 0 +extern "C" { +# include <glib.h> +# include <glib-object.h> +} +#else +# define LL_QTWEBKIT_USES_PIXMAPS 0 +#endif // LL_LINUX + +# include "volume_catcher.h" + +#if LL_WINDOWS +# include <direct.h> +#else +# include <unistd.h> +# include <stdlib.h> +#endif + +#if LL_WINDOWS + // *NOTE:Mani - This captures the module handle for the dll. This is used below + // to get the path to this dll for webkit initialization. + // I don't know how/if this can be done with apr... + namespace { HMODULE gModuleHandle;}; + BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) + { + gModuleHandle = (HMODULE) hinstDLL; + return TRUE; + } +#endif + +#ifdef LL_STANDALONE +#include <qglobal.h> +#elif defined(LL_LINUX) +// We don't provide Qt headers for non-standalone, therefore define this here. +// Our prebuilt is built with QT_NAMESPACE undefined. +#define QT_MANGLE_NAMESPACE(name) name +#define Q_INIT_RESOURCE(name) \ + do { extern int QT_MANGLE_NAMESPACE(qInitResources_ ## name) (); \ + QT_MANGLE_NAMESPACE(qInitResources_ ## name) (); } while (0) +#else +// Apparently this symbol doesn't exist in the windows and Mac tar balls provided by LL. +#define Q_INIT_RESOURCE(name) /*nothing*/ +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginWebKit : + public MediaPluginBase, + public LLEmbeddedBrowserWindowObserver +{ +public: + MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginWebKit(); + + /*virtual*/ void receiveMessage(const char *message_string); + +private: + + std::string mProfileDir; + std::string mHostLanguage; + std::string mUserAgent; + bool mCookiesEnabled; + bool mJavascriptEnabled; + bool mPluginsEnabled; + + enum + { + INIT_STATE_UNINITIALIZED, // LLQtWebkit hasn't been set up yet + INIT_STATE_INITIALIZED, // LLQtWebkit has been set up, but no browser window has been created yet. + INIT_STATE_NAVIGATING, // Browser instance has been set up and initial navigate to about:blank has been issued + INIT_STATE_NAVIGATE_COMPLETE, // initial navigate to about:blank has completed + INIT_STATE_WAIT_REDRAW, // First real navigate begin has been received, waiting for page changed event to start handling redraws + INIT_STATE_WAIT_COMPLETE, // Waiting for first real navigate complete event + INIT_STATE_RUNNING // All initialization gymnastics are complete. + }; + int mBrowserWindowId; + int mInitState; + std::string mInitialNavigateURL; + bool mNeedsUpdate; + + bool mCanCut; + bool mCanCopy; + bool mCanPaste; + int mLastMouseX; + int mLastMouseY; + bool mFirstFocus; + F32 mBackgroundR; + F32 mBackgroundG; + F32 mBackgroundB; + + VolumeCatcher mVolumeCatcher; + + void setInitState(int state) + { +// std::cerr << "changing init state to " << state << std::endl; + mInitState = state; + } + + //////////////////////////////////////////////////////////////////////////////// + // + void update(int milliseconds) + { +#if LL_QTLINUX_DOESNT_HAVE_GLIB + // pump glib generously, as Linux browser plugins are on the + // glib main loop, even if the browser itself isn't - ugh + // This is NOT NEEDED if Qt itself was built with glib + // mainloop integration. + GMainContext *mainc = g_main_context_default(); + while(g_main_context_iteration(mainc, FALSE)); +#endif // LL_QTLINUX_DOESNT_HAVE_GLIB + + // pump qt + LLQtWebKit::getInstance()->pump( milliseconds ); + + mVolumeCatcher.pump(); + + checkEditState(); + + if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) + { + if(!mInitialNavigateURL.empty()) + { + // We already have the initial navigate URL -- kick off the navigate. + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL ); + mInitialNavigateURL.clear(); + } + } + + if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate ) + { + const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); + + unsigned int rowspan = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ); + unsigned int height = LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId ); +#if !LL_QTWEBKIT_USES_PIXMAPS + unsigned int buffer_size = rowspan * height; +#endif // !LL_QTWEBKIT_USES_PIXMAPS + +// std::cerr << "webkit plugin: updating" << std::endl; + + // TODO: should get rid of this memcpy if possible + if ( mPixels && browser_pixels ) + { +// std::cerr << " memcopy of " << buffer_size << " bytes" << std::endl; + +#if LL_QTWEBKIT_USES_PIXMAPS + // copy the pixel data upside-down because of the co-ord system + for (int y=0; y<height; ++y) + { + memcpy( &mPixels[(height-y-1)*rowspan], &browser_pixels[y*rowspan], rowspan ); + } +#else + memcpy( mPixels, browser_pixels, buffer_size ); +#endif // LL_QTWEBKIT_USES_PIXMAPS + } + + if ( mWidth > 0 && mHeight > 0 ) + { +// std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl; + setDirty( 0, 0, mWidth, mHeight ); + } + + mNeedsUpdate = false; + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + bool initBrowser() + { + // already initialized + if ( mInitState > INIT_STATE_UNINITIALIZED ) + return true; + + // set up directories + char cwd[ FILENAME_MAX ]; // I *think* this is defined on all platforms we use + if (NULL == getcwd( cwd, FILENAME_MAX - 1 )) + { + llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl; + return false; + } + std::string application_dir = std::string( cwd ); + +#if LL_LINUX + // take care to initialize glib properly, because some + // versions of Qt don't, and we indirectly need it for (some + // versions of) Flash to not crash the browser. + if (!g_thread_supported ()) g_thread_init (NULL); + g_type_init(); +#endif + +#if LL_DARWIN + // When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on. + // This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger. + // This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it + // which gets hit when the plugin is probed by webkit. + // Unsetting the environment variable here works around this issue. + unsetenv("USERBREAK"); +#endif + +#if LL_WINDOWS + //*NOTE:Mani - On windows, at least, the component path is the + // location of this dll's image file. + std::string component_dir; + char dll_path[_MAX_PATH]; + DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH); + while(len && dll_path[ len ] != ('\\') ) + { + len--; + } + if(len >= 0) + { + dll_path[len] = 0; + component_dir = dll_path; + } + else + { + // *NOTE:Mani - This case should be an rare exception. + // GetModuleFileNameA should always give you a full path, no? + component_dir = application_dir; + } +#else + std::string component_dir = application_dir; +#endif + + // window handle - needed on Windows and must be app window. +#if LL_WINDOWS + char window_title[ MAX_PATH ]; + GetConsoleTitleA( window_title, MAX_PATH ); + void* native_window_handle = (void*)FindWindowA( NULL, window_title ); +#else + void* native_window_handle = 0; +#endif + + // main browser initialization + bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle ); + if ( result ) + { + mInitState = INIT_STATE_INITIALIZED; + + return true; + }; + + return false; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + bool initBrowserWindow() + { + // already initialized + if ( mInitState > INIT_STATE_INITIALIZED ) + return true; + + // not enough information to initialize the browser yet. + if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || + mTextureWidth < 0 || mTextureHeight < 0 ) + { + return false; + }; + + // Set up host language before creating browser window + if(!mHostLanguage.empty()) + { + LLQtWebKit::getInstance()->setHostLanguage(mHostLanguage); + } + + // turn on/off cookies based on what host app tells us + LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled ); + + // turn on/off plugins based on what host app tells us + LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled ); + + // turn on/off Javascript based on what host app tells us + LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled ); + + // create single browser window +#if LLQTWEBKIT_API_VERSION >= 2 + mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow(mWidth, mHeight /*, mTarget*/ ); // We don't have mTarget yet. +#else + mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight ); +#endif + + // tell LLQtWebKit about the size of the browser window + LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); + + // observer events that LLQtWebKit emits + LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); + + // append details to agent string + LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent ); + +// Viewer 2+ -- MC +#if LL_WINDOWS + // Set up window open behavior + LLQtWebKit::getInstance()->setWindowOpenBehavior(mBrowserWindowId, LLQtWebKit::WOB_SIMULATE_BLANK_HREF_CLICK); +#endif + +#if !LL_QTWEBKIT_USES_PIXMAPS + // don't flip bitmap + LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); +#endif // !LL_QTWEBKIT_USES_PIXMAPS + + // set background color + // convert background color channels from [0.0, 1.0] to [0, 255]; + LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) ); + + // Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns. + setInitState(INIT_STATE_NAVIGATING); + + // Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. + // FIXME: Re-added this because navigating to a "page" initializes things correctly - especially + // for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date. + // Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E" + // where RRGGBB is the background color in HTML style + std::stringstream url; + + url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#"; + // convert background color channels from [0.0, 1.0] to [0, 255]; + url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f); + url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f); + url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f); + url << "%22%3E%3C/body%3E%3C/html%3E"; + + lldebugs << "data url is: " << url.str() << llendl; + + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() ); +// LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" ); + + return true; + } + + void setVolume(F32 vol); + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onCursorChanged(const EventType& event) + { + LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue(); + std::string name; + + switch(llqt_cursor) + { + case LLQtWebKit::C_ARROW: + name = "arrow"; + break; + case LLQtWebKit::C_IBEAM: + name = "ibeam"; + break; + case LLQtWebKit::C_SPLITV: + name = "splitv"; + break; + case LLQtWebKit::C_SPLITH: + name = "splith"; + break; + case LLQtWebKit::C_POINTINGHAND: + name = "hand"; + break; + + default: + llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl; + break; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed"); + message.setValue("name", name); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onPageChanged( const EventType& event ) + { + if(mInitState == INIT_STATE_WAIT_REDRAW) + { + setInitState(INIT_STATE_WAIT_COMPLETE); + } + + // flag that an update is required + mNeedsUpdate = true; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateBegin(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); + message.setValue("uri", event.getEventUri()); + sendMessage(message); + + setStatus(STATUS_LOADING); + } + + if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) + { + // Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary. +// setInitState(INIT_STATE_WAIT_REDRAW); + setInitState(INIT_STATE_WAIT_COMPLETE); + } + + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateComplete(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + if(mInitState < INIT_STATE_RUNNING) + { + setInitState(INIT_STATE_RUNNING); + + // Clear the history, so the "back" button doesn't take you back to "about:blank". + LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); + message.setValue("uri", event.getEventUri()); + message.setValueS32("result_code", event.getIntValue()); + message.setValue("result_string", event.getStringValue()); + message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); + message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD)); + sendMessage(message); + + setStatus(STATUS_LOADED); + } + else if(mInitState == INIT_STATE_NAVIGATING) + { + setInitState(INIT_STATE_NAVIGATE_COMPLETE); + } + + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onUpdateProgress(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress"); + message.setValueS32("percent", event.getIntValue()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onStatusTextChange(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text"); + message.setValue("status", event.getStringValue()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onTitleChange(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); + message.setValue("name", event.getStringValue()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onLocationChange(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed"); + message.setValue("uri", event.getEventUri()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onClickLinkHref(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href"); +#if LLQTWEBKIT_API_VERSION >= 2 + message.setValue("uri", event.getEventUri()); + message.setValue("target", event.getStringValue()); + message.setValue("uuid", event.getStringValue2()); +#else + // This will work as long as we don't need "uuid", which will be needed for MoaP. + message.setValue("uri", event.getStringValue()); + message.setValue("target", event.getStringValue2()); + message.setValueU32("target_type", event.getLinkType()); +#endif + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onClickLinkNoFollow(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow"); +#if LLQTWEBKIT_API_VERSION >= 2 + message.setValue("uri", event.getEventUri()); +#else + message.setValue("uri", event.getStringValue()); +#endif + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onCookieChanged(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookie_set"); + message.setValue("cookie", event.getStringValue()); + // These could be passed through as well, but aren't really needed. +// message.setValue("uri", event.getEventUri()); +// message.setValueBoolean("dead", (event.getIntValue() != 0)) + sendMessage(message); + } + + LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers) + { + int result = 0; + + if(modifiers.find("shift") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_SHIFT; + + if(modifiers.find("alt") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_ALT; + + if(modifiers.find("control") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_CONTROL; + + if(modifiers.find("meta") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_META; + + return (LLQtWebKit::EKeyboardModifier)result; + } + + //////////////////////////////////////////////////////////////////////////////// + // + void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers ) + { + native_scan_code = 0; + native_virtual_key = 0; + native_modifiers = 0; + + if( native_key_data.isMap() ) + { +#if LL_DARWIN + native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger()); + native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger()); + native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); +#elif LL_WINDOWS + native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); + native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); + // TODO: I don't think we need to do anything with native modifiers here -- please verify +#elif LL_LINUX + native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); + native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); + native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); +#else + // Add other platforms here as needed +#endif + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) + { + // The incoming values for 'key' will be the ones from indra_constants.h + std::string utf8_text; + + if(key < KEY_SPECIAL) + { + // Low-ascii characters need to get passed through. + utf8_text = (char)key; + } + + // Any special-case handling we want to do for particular keys... + switch((KEY)key) + { + // ASCII codes for some standard keys + case LLQtWebKit::KEY_BACKSPACE: utf8_text = (char)8; break; + case LLQtWebKit::KEY_TAB: utf8_text = (char)9; break; + case LLQtWebKit::KEY_RETURN: utf8_text = (char)13; break; + case LLQtWebKit::KEY_PAD_RETURN: utf8_text = (char)13; break; + case LLQtWebKit::KEY_ESCAPE: utf8_text = (char)27; break; + + default: + break; + } + +// std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl; + + uint32_t native_scan_code = 0; + uint32_t native_virtual_key = 0; + uint32_t native_modifiers = 0; + deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); + + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); + + checkEditState(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) + { + uint32_t key = LLQtWebKit::KEY_NONE; + +// std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl; + + if(utf8str.size() == 1) + { + // The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character. + // In this case, use it as the key value. + key = utf8str[0]; + } + + uint32_t native_scan_code = 0; + uint32_t native_virtual_key = 0; + uint32_t native_modifiers = 0; + deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); + + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); + + checkEditState(); + }; + + void checkEditState(void) + { + bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT); + bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY); + bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE); + + if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); + + if(can_cut != mCanCut) + { + mCanCut = can_cut; + message.setValueBoolean("cut", can_cut); + } + + if(can_copy != mCanCopy) + { + mCanCopy = can_copy; + message.setValueBoolean("copy", can_copy); + } + + if(can_paste != mCanPaste) + { + mCanPaste = can_paste; + message.setValueBoolean("paste", can_paste); + } + + sendMessage(message); + + } + } + +}; + +MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : + MediaPluginBase(host_send_func, host_user_data) +{ +// std::cerr << "MediaPluginWebKit constructor" << std::endl; + + mBrowserWindowId = 0; + mInitState = INIT_STATE_UNINITIALIZED; + mNeedsUpdate = true; + mCanCut = false; + mCanCopy = false; + mCanPaste = false; + mLastMouseX = 0; + mLastMouseY = 0; + mFirstFocus = true; + mBackgroundR = 0.0f; + mBackgroundG = 0.0f; + mBackgroundB = 0.0f; + + mHostLanguage = "en"; // default to english + mJavascriptEnabled = true; // default to on + mPluginsEnabled = true; // default to on + mUserAgent = "LLPluginMedia Web Browser"; + + // Initialize WebCore resource. + Q_INIT_RESOURCE(WebCore); +} + +MediaPluginWebKit::~MediaPluginWebKit() +{ + // unhook observer + LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); + + // clean up + LLQtWebKit::getInstance()->reset(); + +// std::cerr << "MediaPluginWebKit destructor" << std::endl; +} + +void MediaPluginWebKit::receiveMessage(const char *message_string) +{ +// std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; + message.setValueLLSD("versions", versions); + + std::string plugin_version = "Webkit media plugin, Webkit version "; + plugin_version += LLQtWebKit::getInstance()->getVersion(); + message.setValue("plugin_version", plugin_version); + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + F64 time = message_in.getValueReal("time"); + + // Convert time to milliseconds for update() + update((int)(time * 1000.0f)); + } + else if(message_name == "cleanup") + { + // DTOR most likely won't be called but the recent change to the way this process + // is (not) killed means we see this message and can do what we need to here. + // Note: this cleanup is ultimately what writes cookies to the disk + LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); + LLQtWebKit::getInstance()->reset(); + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + +// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name +// << ", size: " << info.mSize +// << ", address: " << info.mAddress +// << std::endl; + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + +// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl; + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + } + mSharedSegments.erase(iter); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if(message_name == "set_volume") + { + F32 volume = message_in.getValueReal("volume"); + setVolume(volume); + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "init") + { + // This is the media init message -- all necessary data for initialization should have been received. + if(initBrowser()) + { + + // Plugin gets to decide the texture parameters to use. + mDepth = 4; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + message.setValueS32("default_width", 1024); + message.setValueS32("default_height", 1024); + message.setValueS32("depth", mDepth); + message.setValueU32("internalformat", GL_RGBA); + #if LL_QTWEBKIT_USES_PIXMAPS + message.setValueU32("format", GL_BGRA_EXT); // I hope this isn't system-dependant... is it? If so, we'll have to check the root window's pixel layout or something... yuck. + #else + message.setValueU32("format", GL_RGBA); + #endif // LL_QTWEBKIT_USES_PIXMAPS + message.setValueU32("type", GL_UNSIGNED_BYTE); + message.setValueBoolean("coords_opengl", true); + sendMessage(message); + } + else + { + // if initialization failed, we're done. + mDeleteMe = true; + } + + } + else if(message_name == "set_user_data_path") + { + std::string user_data_path = message_in.getValue("path"); // n.b. always has trailing platform-specific dir-delimiter + mProfileDir = user_data_path + "browser_profile"; + + // FIXME: Should we do anything with this if it comes in after the browser has been initialized? + } + else if(message_name == "set_language_code") + { + mHostLanguage = message_in.getValue("language"); + + // FIXME: Should we do anything with this if it comes in after the browser has been initialized? + } + else if(message_name == "plugins_enabled") + { + mPluginsEnabled = message_in.getValueBoolean("enable"); + } + else if(message_name == "javascript_enabled") + { + mJavascriptEnabled = message_in.getValueBoolean("enable"); + } + else if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + mBackgroundR = message_in.getValueReal("background_r"); + mBackgroundG = message_in.getValueReal("background_g"); + mBackgroundB = message_in.getValueReal("background_b"); +// mBackgroundA = message_in.setValueReal("background_a"); // Ignore any alpha + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + mPixels = (unsigned char*)iter->second.mAddress; + mWidth = width; + mHeight = height; + + if(initBrowserWindow()) + { + + // size changed so tell the browser + LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); + + // std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight + // << ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl; + + S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); + + // The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response. + if(real_width <= texture_width) + { + texture_width = real_width; + } + else + { + // This won't work -- it'll be bigger than the allocated memory. This is a fatal error. + // std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl; + mDeleteMe = true; + return; + } + } + else + { + // Setting up the browser window failed. This is a fatal error. + mDeleteMe = true; + } + + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + }; + }; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + } + else if(message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + +// std::cout << "loading URI: " << uri << std::endl; + + if(!uri.empty()) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri ); + } + else + { + mInitialNavigateURL = uri; + } + } + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 button = message_in.getValueS32("button"); + mLastMouseX = message_in.getValueS32("x"); + mLastMouseY = message_in.getValueS32("y"); + std::string modifiers = message_in.getValue("modifiers"); + + // Treat unknown mouse events as mouse-moves. + LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE; + if(event == "down") + { + mouse_event = LLQtWebKit::ME_MOUSE_DOWN; + } + else if(event == "up") + { + mouse_event = LLQtWebKit::ME_MOUSE_UP; + } + else if(event == "double_click") + { + mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK; + } + + LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers)); + checkEditState(); + } + else if(message_name == "scroll_event") + { + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + std::string modifiers = message_in.getValue("modifiers"); + + // Incoming scroll events are adjusted so that 1 detent is approximately 1 unit. + // Qt expects 1 detent to be 120 units. + // It also seems that our y scroll direction is inverted vs. what Qt expects. + + x *= 120; + y *= -120; + + LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers)); + } + else if(message_name == "key_event") + { + std::string event = message_in.getValue("event"); + S32 key = message_in.getValueS32("key"); + std::string modifiers = message_in.getValue("modifiers"); + LLSD native_key_data = message_in.getValueLLSD("native_key_data"); + + // Treat unknown events as key-up for safety. + LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP; + if(event == "down") + { + key_event = LLQtWebKit::KE_KEY_DOWN; + } + else if(event == "repeat") + { + key_event = LLQtWebKit::KE_KEY_REPEAT; + } + + keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data); + } + else if(message_name == "text_event") + { + std::string text = message_in.getValue("text"); + std::string modifiers = message_in.getValue("modifiers"); + LLSD native_key_data = message_in.getValueLLSD("native_key_data"); + + unicodeInput(text, decodeModifiers(modifiers), native_key_data); + } + if(message_name == "edit_cut") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT ); + checkEditState(); + } + if(message_name == "edit_copy") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY ); + checkEditState(); + } + if(message_name == "edit_paste") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE ); + checkEditState(); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; + }; + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) + { + if(message_name == "focus") + { + bool val = message_in.getValueBoolean("focused"); + LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val ); + + if(mFirstFocus && val) + { + // On the first focus, post a tab key event. This fixes a problem with initial focus. + std::string empty; + keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty)); + keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty)); + mFirstFocus = false; + } + } + else if(message_name == "clear_cache") + { + LLQtWebKit::getInstance()->clearCache(); + } + else if(message_name == "clear_cookies") + { + LLQtWebKit::getInstance()->clearAllCookies(); + } + else if(message_name == "enable_cookies") + { + mCookiesEnabled = message_in.getValueBoolean("enable"); + LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled ); + } + else if(message_name == "enable_plugins") + { + mPluginsEnabled = message_in.getValueBoolean("enable"); + LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled ); + } + else if(message_name == "enable_javascript") + { + mJavascriptEnabled = message_in.getValueBoolean("enable"); + //LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled ); + } + else if(message_name == "set_cookies") + { + LLQtWebKit::getInstance()->setCookies(message_in.getValue("cookies")); + } + else if(message_name == "proxy_setup") + { + bool val = message_in.getValueBoolean("enable"); + std::string host = message_in.getValue("host"); + int port = message_in.getValueS32("port"); + LLQtWebKit::getInstance()->enableProxy( val, host, port ); + } + else if(message_name == "browse_stop") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP ); + } + else if(message_name == "browse_reload") + { + // foo = message_in.getValueBoolean("ignore_cache"); + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD ); + } + else if(message_name == "browse_forward") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD ); + } + else if(message_name == "browse_back") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK ); + } + else if(message_name == "set_status_redirect") + { + int code = message_in.getValueS32("code"); + std::string url = message_in.getValue("url"); + if ( 404 == code ) // browser lib only supports 404 right now + { + LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url ); + }; + } + else if(message_name == "set_user_agent") + { + mUserAgent = message_in.getValue("user_agent"); + LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent ); + } + else if(message_name == "init_history") + { + // Initialize browser history + LLSD history = message_in.getValueLLSD("history"); + // First, clear the URL history + LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); + // Then, add the history items in order + LLSD::array_iterator iter_history = history.beginArray(); + LLSD::array_iterator end_history = history.endArray(); + for(; iter_history != end_history; ++iter_history) + { + std::string url = (*iter_history).asString(); + if(! url.empty()) { + LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url); + } + } + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl; + }; + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl; + }; + } +} + +void MediaPluginWebKit::setVolume(F32 volume) +{ + mVolumeCatcher.setVolume(volume); +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data); + *plugin_send_func = MediaPluginWebKit::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} + diff --git a/linden/indra/media_plugins/webkit/volume_catcher.h b/linden/indra/media_plugins/webkit/volume_catcher.h new file mode 100644 index 000000000..855e99fc0 --- /dev/null +++ b/linden/indra/media_plugins/webkit/volume_catcher.h @@ -0,0 +1,61 @@ +/** + * @file volume_catcher.h + * @brief Interface to a class with platform-specific implementations that allows control of the audio volume of all sources in the current process. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef VOLUME_CATCHER_H +#define VOLUME_CATCHER_H + +#include "linden_common.h" + +class VolumeCatcherImpl; + +class VolumeCatcher +{ + public: + VolumeCatcher(); + ~VolumeCatcher(); + + void setVolume(F32 volume); // 0.0 - 1.0 + + // Set the left-right pan of audio sources + // where -1.0 = left, 0 = center, and 1.0 = right + void setPan(F32 pan); + + void pump(); // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume + + private: + VolumeCatcherImpl *pimpl; +}; + +#endif // VOLUME_CATCHER_H diff --git a/linden/indra/media_plugins/webkit/windows_volume_catcher.cpp b/linden/indra/media_plugins/webkit/windows_volume_catcher.cpp new file mode 100644 index 000000000..64f70c419 --- /dev/null +++ b/linden/indra/media_plugins/webkit/windows_volume_catcher.cpp @@ -0,0 +1,126 @@ +/** + * @file windows_volume_catcher.cpp + * @brief A Windows implementation of volume level control of all audio channels opened by a process. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "volume_catcher.h" +# define WIN32_LEAN_AND_MEAN +# include <winsock2.h> +#include <windows.h> +#include "llmemory.h" +class VolumeCatcherImpl : public LLSingleton<VolumeCatcherImpl> +{ +friend LLSingleton<VolumeCatcherImpl>; +public: + + void setVolume(F32 volume); + void setPan(F32 pan); + +private: + // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance. + VolumeCatcherImpl(); + ~VolumeCatcherImpl(); + + typedef void (WINAPI *set_volume_func_t)(F32); + typedef void (WINAPI *set_mute_func_t)(bool); + + set_volume_func_t mSetVolumeFunc; + set_mute_func_t mSetMuteFunc; + + F32 mVolume; + F32 mPan; +}; +VolumeCatcherImpl::VolumeCatcherImpl() +: mVolume(1.0f), // default volume is max + mPan(0.f) // default pan is centered +{ + HMODULE handle = ::LoadLibrary(L"winmm.dll"); + if(handle) + { + mSetVolumeFunc = (set_volume_func_t)::GetProcAddress(handle, "setPluginVolume"); + mSetMuteFunc = (set_mute_func_t)::GetProcAddress(handle, "setPluginMute"); + } +} + +VolumeCatcherImpl::~VolumeCatcherImpl() +{ +} + + +void VolumeCatcherImpl::setVolume(F32 volume) +{ + mVolume = volume; + + if (mSetMuteFunc) + { + mSetMuteFunc(volume == 0.f); + } + if (mSetVolumeFunc) + { + mSetVolumeFunc(mVolume); + } +} + +void VolumeCatcherImpl::setPan(F32 pan) +{ // remember pan for calculating individual channel levels later + mPan = pan; +} + +///////////////////////////////////////////////////// + +VolumeCatcher::VolumeCatcher() +{ + pimpl = VolumeCatcherImpl::getInstance(); +} + +VolumeCatcher::~VolumeCatcher() +{ + // Let the instance persist until exit. +} + +void VolumeCatcher::setVolume(F32 volume) +{ + pimpl->setVolume(volume); +} + +void VolumeCatcher::setPan(F32 pan) +{ + pimpl->setPan(pan); +} + +void VolumeCatcher::pump() +{ + // No periodic tasks are necessary for this implementation. +} + + diff --git a/linden/indra/newview/CMakeLists.txt b/linden/indra/newview/CMakeLists.txt index dfd35bf31..e6c17678d 100644 --- a/linden/indra/newview/CMakeLists.txt +++ b/linden/indra/newview/CMakeLists.txt @@ -21,8 +21,8 @@ include(LLImage) include(LLImageJ2COJ) include(LLInventory) include(LLMath) -include(LLMedia) include(LLMessage) +include(LLPlugin) include(LLPrimitive) include(LLRender) include(LLUI) @@ -31,7 +31,6 @@ include(LLWindow) include(LLXML) include(LScript) include(Linking) -include(Mozlib) include(NDOF) include(GooglePerfTools) include(TemplateCheck) @@ -55,8 +54,8 @@ include_directories( ${LLIMAGE_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} - ${LLMEDIA_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} + ${LLPLUGIN_INCLUDE_DIRS} ${LLPRIMITIVE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLUI_INCLUDE_DIRS} @@ -65,7 +64,6 @@ include_directories( ${LLXML_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS}/lscript_compile - ${GSTREAMER_INCLUDE_DIRS} ) set(viewer_SOURCE_FILES @@ -84,9 +82,9 @@ set(viewer_SOURCE_FILES floaterlocalassetbrowse.cpp floatervoicelicense.cpp hbfloatergrouptitles.cpp - hippoGridManager.cpp - hippoLimits.cpp - hippoRestRequest.cpp + hippogridmanager.cpp + hippolimits.cpp + hipporestrequest.cpp impprefsfonts.cpp jcfloater_animation_list.cpp jcfloaterareasearch.cpp @@ -186,9 +184,8 @@ set(viewer_SOURCE_FILES llfloatergroups.cpp llfloaterhandler.cpp llfloaterhardwaresettings.cpp - llfloaterhtml.cpp llfloaterhtmlcurrency.cpp - llfloaterhtmlhelp.cpp + llfloatermediabrowser.cpp llfloaterhtmlsimple.cpp llfloaterhud.cpp llfloaterimagepreview.cpp @@ -200,6 +197,8 @@ set(viewer_SOURCE_FILES llfloaterlandmark.cpp llfloatermap.cpp llfloatermemleak.cpp + llfloatermessagebuilder.cpp + llfloatermessagelog.cpp llfloatermute.cpp llfloaternamedesc.cpp llfloaternewim.cpp @@ -313,10 +312,12 @@ set(viewer_SOURCE_FILES llpanelinput.cpp llpanelinventory.cpp llpanelland.cpp + llpanellandaudio.cpp llpanellandmedia.cpp llpanellandobjects.cpp llpanellandoptions.cpp llpanellogin.cpp + llpanelmediahud.cpp llpanelmsgs.cpp llpanelnetwork.cpp llpanelobject.cpp @@ -332,6 +333,7 @@ set(viewer_SOURCE_FILES llpolymorph.cpp llprefsadvanced.cpp llprefschat.cpp + llprefscolors.cpp llprefsim.cpp llprefsvoice.cpp llpreviewanim.cpp @@ -422,6 +424,8 @@ set(viewer_SOURCE_FILES llviewerkeyboard.cpp llviewerlayer.cpp llviewermedia.cpp + llviewermediafocus.cpp + llviewermedia_streamingaudio.cpp llviewermenu.cpp llviewermenufile.cpp llviewermessage.cpp @@ -468,7 +472,7 @@ set(viewer_SOURCE_FILES llwearable.cpp llwearablelist.cpp llweb.cpp - llwebbrowserctrl.cpp + llmediactrl.cpp llwindlightremotectrl.cpp llwind.cpp llwlanimator.cpp @@ -484,6 +488,7 @@ set(viewer_SOURCE_FILES panelradarentry.cpp pipeline.cpp primbackup.cpp + qtoolalign.cpp rlvhandler.cpp rlvhelper.cpp rlvcommon.cpp @@ -492,6 +497,11 @@ set(viewer_SOURCE_FILES rlvfloaterbehaviour.cpp viewertime.cpp viewerversion.cpp + windlightsettingsupdate.cpp + wlfloatermanager.cpp + wlfloaterwindlightsend.cpp + wlretrievesettings.cpp + wlsettingsmanager.cpp ) set(VIEWER_BINARY_NAME "imprudence-bin" CACHE STRING @@ -525,9 +535,9 @@ set(viewer_HEADER_FILES floaterlocalassetbrowse.h floatervoicelicense.h hbfloatergrouptitles.h - hippoGridManager.h - hippoLimits.h - hippoRestRequest.h + hippogridmanager.h + hippolimits.h + hipporestrequest.h impprefsfonts.h jcfloater_animation_list.h jcfloaterareasearch.h @@ -632,9 +642,8 @@ set(viewer_HEADER_FILES llfloatergroups.h llfloaterhandler.h llfloaterhardwaresettings.h - llfloaterhtml.h llfloaterhtmlcurrency.h - llfloaterhtmlhelp.h + llfloatermediabrowser.h llfloaterhtmlsimple.h llfloaterhud.h llfloaterimagepreview.h @@ -646,6 +655,8 @@ set(viewer_HEADER_FILES llfloaterlandmark.h llfloatermap.h llfloatermemleak.h + llfloatermessagebuilder.h + llfloatermessagelog.h llfloatermute.h llfloaternamedesc.h llfloaternewim.h @@ -758,11 +769,13 @@ set(viewer_HEADER_FILES llpanelinput.h llpanelinventory.h llpanelland.h + llpanellandaudio.h llpanellandmedia.h llpanellandobjects.h llpanellandoptions.h llpanelLCD.h llpanellogin.h + llpanelmediahud.h llpanelmsgs.h llpanelnetwork.h llpanelobject.h @@ -778,6 +791,7 @@ set(viewer_HEADER_FILES llpolymorph.h llprefsadvanced.h llprefschat.h + llprefscolors.h llprefsim.h llprefsvoice.h llpreview.h @@ -869,6 +883,8 @@ set(viewer_HEADER_FILES llviewerkeyboard.h llviewerlayer.h llviewermedia.h + llviewermediaobserver.h + llviewermediafocus.h llviewermenu.h llviewermenufile.h llviewermessage.h @@ -917,7 +933,7 @@ set(viewer_HEADER_FILES llwearable.h llwearablelist.h llweb.h - llwebbrowserctrl.h + llmediactrl.h llwind.h llwindebug.h llwindlightremotectrl.h @@ -936,6 +952,7 @@ set(viewer_HEADER_FILES panelradarentry.h pipeline.h primbackup.h + qtoolalign.h randgauss.h rlvdefines.h rlvhandler.h @@ -948,6 +965,10 @@ set(viewer_HEADER_FILES VorbisFramework.h viewertime.h viewerversion.h + wlfloatermanager.h + wlfloaterwindlightsend.h + wlretrievesettings.h + wlsettingsmanager.h ) source_group("CMake Rules" FILES ViewerInstall.cmake) @@ -1120,6 +1141,7 @@ if (WINDOWS) if (INTEL_MEMOPS_LIBRARY) list(APPEND viewer_LIBRARIES ${INTEL_MEMOPS_LIBRARY}) endif (INTEL_MEMOPS_LIBRARY) + use_prebuilt_binary(dbghelp) endif (WINDOWS) # Add the xui files. This is handy for searching for xui elements @@ -1164,6 +1186,7 @@ set(viewer_APPSETTINGS_FILES app_settings/anim.ini app_settings/ao_template.ini app_settings/cmd_line.xml + app_settings/default_grids.xml app_settings/grass.xml app_settings/high_graphics.xml app_settings/keys.ini @@ -1334,6 +1357,7 @@ if (WINDOWS) --channel=${VIEWER_CHANNEL} --login_channel=${VIEWER_LOGIN_CHANNEL} --standalone=${STANDALONE} + --buildtype=${CMAKE_BUILD_TYPE} --grid=${GRID} --source=${CMAKE_CURRENT_SOURCE_DIR} --artwork=${ARTWORK_DIR} @@ -1342,6 +1366,9 @@ if (WINDOWS) --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/touched.bat DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) + + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit) # Removed media_plugin_gstreamer010 + if (PACKAGE) add_custom_target(package ALL DEPENDS ${CMAKE_CFG_INTDIR}/touched.bat) add_dependencies(package windows-updater windows-crash-logger) @@ -1354,8 +1381,8 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLIMAGE_LIBRARIES} ${LLIMAGEJ2COJ_LIBRARIES} ${LLINVENTORY_LIBRARIES} - ${LLMEDIA_LIBRARIES} ${LLMESSAGE_LIBRARIES} + ${LLPLUGIN_LIBRARIES} ${LLPRIMITIVE_LIBRARIES} ${LLRENDER_LIBRARIES} ${FREETYPE_LIBRARIES} @@ -1377,7 +1404,6 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${OPENGL_LIBRARIES} ${FMODWRAPPER_LIBRARY} ${OPENGL_LIBRARIES} - ${MOZLIB_LIBRARIES} ${JSONCPP_LIBRARIES} ${SDL_LIBRARY} ${SMARTHEAP_LIBRARY} @@ -1410,6 +1436,7 @@ if (LINUX) ARGS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py --standalone=${STANDALONE} + --buildtype=${CMAKE_BUILD_TYPE} --grid=${GRID} --channel=${VIEWER_CHANNEL} --login_channel=${VIEWER_LOGIN_CHANNEL} @@ -1422,6 +1449,8 @@ if (LINUX) --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched DEPENDS imprudence-stripped ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) + + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer010 media_plugin_webkit) if (NOT INSTALL) add_custom_target(package ALL DEPENDS ${product}.tar.bz2) @@ -1459,6 +1488,8 @@ if (DARWIN) --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) + + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit media_plugin_gstreamer010) if (PACKAGE) add_custom_target(package ALL DEPENDS ${VIEWER_BINARY_NAME}) @@ -1470,6 +1501,7 @@ if (DARWIN) ARGS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py --standalone=${STANDALONE} + --buildtype=${CMAKE_BUILD_TYPE} --grid=${GRID} --configuration=${CMAKE_CFG_INTDIR} --channel=${VIEWER_CHANNEL} @@ -1479,11 +1511,12 @@ if (DARWIN) --build=${CMAKE_CURRENT_BINARY_DIR} --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) - + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit media_plugin_gstreamer010) add_custom_command( TARGET package POST_BUILD COMMAND ${PYTHON_EXECUTABLE} @@ -1509,4 +1542,91 @@ if (INSTALL) include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake) endif (INSTALL) -ADD_VIEWER_BUILD_TEST(llagentaccess viewer) +#ADD_VIEWER_BUILD_TEST(llagentaccess viewer) + +# Don't do these for DARWIN or LINUX here -- they're taken care of by viewer_manifest.py +if (WINDOWS) + + get_target_property(BUILT_LLCOMMON llcommon LOCATION) + add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + copy_if_different + ${BUILT_LLCOMMON} + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} + COMMENT "Copying llcommon.dll to the runtime folder." + ) + + get_target_property(BUILT_SLPLUGIN SLPlugin LOCATION) + add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + copy_if_different + ${BUILT_SLPLUGIN} + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} + COMMENT "Copying SLPlugin executable to the runtime folder." + ) + + get_target_property(BUILT_WEBKIT_PLUGIN media_plugin_webkit LOCATION) + add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + copy_if_different + ${BUILT_WEBKIT_PLUGIN} + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin + COMMENT "Copying WebKit Plugin to the runtime folder." + ) + + #get_target_property(BUILT_GSTREAMER_PLUGIN media_plugin_gstreamer010 LOCATION) + # add_custom_command( + # TARGET ${VIEWER_BINARY_NAME} POST_BUILD + # COMMAND ${CMAKE_COMMAND} + # ARGS + # -E + # copy_if_different + # ${BUILT_GSTREAMER_PLUGIN} + # ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin + # COMMENT "Copying Gstreamer Plugin to the runtime folder." + # ) + + get_target_property(BUILT_QUICKTIME_PLUGIN media_plugin_quicktime LOCATION) + add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + copy_if_different + ${BUILT_QUICKTIME_PLUGIN} + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin + COMMENT "Copying Quicktime Plugin to the runtime folder." + ) + + # Copying the mime_types.xml file to app_settings + set(mime_types_source "${CMAKE_SOURCE_DIR}/newview/skins/default/xui/en-us") + set(mime_types_dest "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/app_settings") + add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + copy_if_different + ${mime_types_source}/mime_types_windows.xml + ${mime_types_dest}/mime_types_windows.xml + COMMENT "Copying mime_types_windows.xml to the runtime app_settings folder." + ) + +endif (WINDOWS) + +if (DARWIN) +# Don't do this here -- it's taken care of by viewer_manifest.py +# add_custom_command(TARGET ${VIEWER_BINARY_NAME} POST_BUILD +# COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin/ +# DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib +# ) +endif (DARWIN) diff --git a/linden/indra/newview/Info-Imprudence.plist b/linden/indra/newview/Info-Imprudence.plist index 419cacdc8..e7dc82d76 100644 --- a/linden/indra/newview/Info-Imprudence.plist +++ b/linden/indra/newview/Info-Imprudence.plist @@ -32,7 +32,7 @@ </dict> </array> <key>CFBundleVersion</key> - <string>Experimental 2010.09.04</string> + <string>Experimental 2010.10.23</string> <key>CSResourcesFileMapped</key> <true/> </dict> diff --git a/linden/indra/newview/app_settings/default_grids.xml b/linden/indra/newview/app_settings/default_grids.xml index 2c52fa1b7..9817d2df5 100644 --- a/linden/indra/newview/app_settings/default_grids.xml +++ b/linden/indra/newview/app_settings/default_grids.xml @@ -1,10 +1,43 @@ <llsd> + <!-- A copy of this file should be available for download from the + uri specified with the Debug Setting 'GridUpdateList', see + indra/newview/app_settings/settings.xml. --> <array> <map> - <key>default_grids_version</key><string>26</string> + <!-- Bumb this number whenever you change a grid entry. + It will then cause all entries with the same nick to be + overwritten in the users private grid_info.xml file next + time they run the viewer. --> + <key>default_grids_version</key><string>1</string> </map> - <!-- Second Life --> + <!-- Avatrian Tokyo --> + <map> + <key>gridnick</key><string>avatriantokyo</string> + <key>gridname</key><string>Avatrian Tokyo</string> + <key>platform</key><string>OpenSim</string> + <key>loginuri</key><string>http://124.107.67.189:8002/</string> + <key>loginpage</key><string>http://imprudenceviewer.org/app/splash/</string> <!-- REMOVE OR CHANGE THIS --> + <key>website</key><string>http://moonworld.cet.edu/os/</string> + <key>register</key><string>http://moonworld.cet.edu/os/portal/index.php</string> + <key>version</key><string>1</string> + </map> + + <!-- CET Grid --> + <map> + <key>gridnick</key><string>cetgrid</string> + <key>gridname</key><string>CETGrid</string> + <key>platform</key><string>OpenSim</string> + <key>loginuri</key><string>http://198.185.178.76:8002/</string> + <key>loginpage</key><string>http://imprudenceviewer.org/app/splash/</string> <!-- REMOVE OR CHANGE THIS --> + <key>website</key><string>http://moonworld.cet.edu/os/</string> + <key>register</key><string>http://moonworld.cet.edu/os/portal/index.php</string> + <key>version</key><string>1</string> + </map> + + <!-- REMOVE EVERYTHING BELOW --> + + <!-- Second Life --> <map> <key>gridnick</key><string>secondlife</string> <key>gridname</key><string>Second Life</string> @@ -19,21 +52,6 @@ <key>version</key><string>0</string> </map> - <!-- Second Life Beta --> - <map> - <key>gridnick</key><string>secondlifebeta</string> - <key>gridname</key><string>Second Life Beta Grid</string> - <key>platform</key><string>SecondLife</string> - <key>loginuri</key><string>https://login.aditi.lindenlab.com/cgi-bin/login.cgi</string> - <key>loginpage</key><string>http://imprudenceviewer.org/app/splash/</string> - <key>helperuri</key><string>http://aditi-secondlife.webdev.lindenlab.com/helpers/</string> - <key>website</key><string>http://secondlife.com/</string> - <key>support</key><string>http://secondlife.com/support/</string> - <key>register</key><string>http://secondlife.com/registration/</string> - <key>password</key><string>http://secondlife.com/account/request.php</string> - <key>version</key><string>1</string> - </map> - <!-- Local Host --> <map> <key>gridnick</key><string>localhost</string> @@ -45,192 +63,5 @@ <key>version</key><string>1</string> </map> - <!-- OSGrid --> - <map> - <key>gridnick</key><string>osgrid</string> - <key>gridname</key><string>OSGrid</string> - <key>platform</key><string>OpenSim</string> - <key>loginuri</key><string>http://osgrid.org:8002/</string> - <key>loginpage</key><string>http://osgrid.org/loginscreen.php</string> - <key>helperuri</key><string>http://osgrid.org/</string> - <key>website</key><string>http://osgrid.org/</string> - <key>support</key><string>http://osgrid.org/</string> - <key>register</key><string>http://osgrid.org/elgg/account/register.php</string> - <key>password</key><string>http://osgrid.org/elgg/account/forgotten_password.php</string> - <key>version</key><string>1</string> - </map> - - <!-- Legend City Online --> - <map> - <key>gridnick</key><string>legendcityonline</string> - <key>gridname</key><string>Legend City Online</string> - <key>platform</key><string>OpenSim</string> - <key>loginuri</key><string>http://login.legendcityonline.com</string> - <key>loginpage</key><string>http://www.legendcityonline.com/welcome.php</string> - <key>helperuri</key><string>https://secure.legendcityonline.com/</string> - <key>website</key><string>http://www.legendcityonline.com/</string> - <key>support</key><string>http://www.legendcityonline.com/</string> - <key>register</key><string>http://www.legendcityonline.com/</string> - <key>password</key><string>http://www.legendcityonline.com/</string> - <key>version</key><string>0</string> - </map> - - <!-- WorldSimTerra --> - <map> - <key>gridnick</key><string>worldsimterra</string> - <key>gridname</key><string>WorldSimTerra</string> - <key>platform</key><string>OpenSim</string> - <key>loginuri</key><string>http://wsterra.com:8002</string> - <key>loginpage</key><string>http://wsterra.com/log.php</string> - <key>helperuri</key><string>http://wsterra.com/</string> - <key>website</key><string>http://www.worldsimterra.com/</string> - <key>support</key><string>http://www.worldsimterra.com/</string> - <key>register</key><string>http://www.worldsimterra.com/</string> - <key>password</key><string>http://www.worldsimterra.com/</string> - <key>version</key><string>0</string> - </map> - - <!-- Your Alternative Life --> - <map> - <key>gridnick</key><string>youralternativelife</string> - <key>gridname</key><string>Your Alternative Life</string> - <key>platform</key><string>OpenSim</string> - <key>loginuri</key><string>http://grid01.from-ne.com:8002/</string> - <key>loginpage</key><string>http://grid01.from-ne.com/tios/loginscreen3.php</string> - <key>helperuri</key><string>http://grid01.from-ne.com/tios/services/</string> - <key>website</key><string>http://www.youralternativelife.com</string> - <key>support</key><string>http://www.youralternativelife.com</string> - <key>register</key><string>http://www.youralternativelife.com</string> - <key>password</key><string>http://www.youralternativelife.com</string> - <key>version</key><string>0</string> - - </map> - - <!-- The New World Grid --> - <map> - <key>gridnick</key><string>thenewworldgrid</string> - <key>gridname</key><string>The New World Grid</string> - <key>platform</key><string>OpenSim</string> - <key>loginuri</key><string>http://grid.newworldgrid.com:8002/</string> - <key>loginpage</key><string>http://account.newworldgrid.com/loginscreen.php</string> - <key>helperuri</key><string>http://account.newworldgrid.com/</string> - <key>website</key><string>http://www.newworldgrid.com/</string> - <key>support</key><string>http://www.newworldgrid.com/</string> - <key>register</key><string>http://www.newworldgrid.com/register</string> - <key>password</key><string>http://account.newworldgrid.com/</string> - <key>version</key><string>0</string> - </map> - - <!-- ReactionGrid --> - <map> - <key>gridnick</key><string>reactiongrid</string> - <key>gridname</key><string>ReactionGrid</string> - <key>platform</key><string>OpenSim</string> - <key>loginuri</key><string>http://reactiongrid.com:8008/</string> - <key>loginpage</key><string>http://gsquared.info/portal</string> - <key>website</key><string>http://reactiongrid.com/Default.aspx</string> - <key>support</key><string>http://reactiongrid.com/Support.aspx</string> - <key>register</key><string>http://reactiongrid.com/Register.aspx</string> - <key>password</key><string>http://reactiongrid.com/Support/ResetPassword.aspx</string> - <key>version</key><string>0</string> - </map> - - <!-- Cyberlandia --> - <map> - <key>gridnick</key><string>cyberlandia</string> - <key>gridname</key><string>Cyberlandia</string> - <key>platform</key><string>OpenSim</string> - <key>loginuri</key><string>http://grid.cyberlandia.net:8002</string> - <key>loginpage</key><string></string> - <key>helperuri</key><string></string> - <key>website</key><string>http://www.cyberlandia.net</string> - <key>version</key><string>0</string> - </map> - - <!-- Role Play Worlds --> - <map> - <key>gridnick</key><string>roleplayworlds</string> - <key>gridname</key><string>Role Play Worlds</string> - <key>platform</key><string>OpenSim</string> - <key>loginuri</key><string>http://grid.roleplayworlds.net:8002/</string> - <key>loginpage</key><string>http://grid.roleplayworlds.net/loginscreen.php</string> - <key>helperuri</key><string>http://grid.roleplayworlds.net/</string> - <key>website</key><string>http://roleplayworlds.net/</string> - <key>register</key><string>http://grid.roleplayworlds.net/index.php?page=create</string> - <key>password</key><string>http://grid.roleplayworlds.net/index.php?page=change</string> - <key>version</key><string>0</string> - </map> - - <!-- GiantGrid --> - <map> - <key>gridnick</key><string>giantgrid</string> - <key>gridname</key><string>GiantGrid</string> - <key>platform</key><string>OpenSim</string> - <key>loginuri</key><string>http://Gianttest.no-ip.biz:8002/</string> - <key>loginpage</key><string>http://gianttest.no-ip.biz:80/gridsplash?method=login</string> - <key>helperuri</key><string>http://gianttest.no-ip.biz/giantmap/</string> - <key>version</key><string>0</string> - </map> - - <!-- 3rd Rock Grid --> - <map> - <key>gridnick</key><string>3rdrock</string> - <key>gridname</key><string>3rd Rock Grid</string> - <key>platform</key><string>OpenSim</string> - <key>loginuri</key><string>http://grid.3rdrockgrid.com:8002/</string> - <key>loginpage</key><string>http://3rdrockgrid.com/startpage.php</string> - <key>helperuri</key><string>http://grid.3rdrockgrid.com/money/</string> - <key>website</key><string>http://3rdrockgrid.com/</string> - <key>register</key><string>http://3rdrockgrid.com/</string> - <key>password</key><string>http://3rdrockgrid.com/</string> - <key>support</key><string>http://3rdrockgrid.com/</string> - <key>version</key><string>1</string> - </map> - - <!-- InWorldz --> - <map> - <key>gridname</key> <string>Inworldz</string> - <key>gridnick</key> <string>inworldz</string> - <key>platform</key> <string>OpenSim</string> - <key>loginuri</key> <string>http://inworldz.com:8002/</string> - <key>loginpage</key> <string>http://inworldz.com/loginscreen.php</string> - <key>helperuri</key> <string>http://inworldz.com/</string> - <key>password</key> <string>http://inworldz.com/wpassword</string> - <key>register</key> <string>http://inworldz.com/register</string> - <key>support</key> <string>http://inworldz.com/help</string> - <key>website</key> <string>http://inworldz.com/about/</string> - <key>version</key> <string>1</string> - </map> - - <!-- Meta7 --> - <map> - <key>gridname</key> <string>Meta7</string> - <key>gridnick</key> <string>meta7</string> - <key>platform</key> <string>OpenSim</string> - <key>loginuri</key> <string>http://login.meta7.com/</string> - <key>loginpage</key> <string>http://api.meta7.com/loginscreen.php</string> - <key>helperuri</key> <string>https://secure.meta7.com/</string> - <key>password</key> <string>http://www.meta7.com/resetpass.php</string> - <key>register</key> <string>http://www.meta7.com/register.php</string> - <key>support</key> <string>http://www.meta7.com/support.php</string> - <key>website</key> <string>http://meta7.com/</string> - <key>version</key> <string>0</string> - </map> - - <!-- ScienceSim --> - <map> - <key>gridname</key> <string>ScienceSim</string> - <key>gridnick</key> <string>sciencesim</string> - <key>platform</key> <string>OpenSim</string> - <key>loginuri</key> <string>http://grid.sciencesim.com/</string> - <key>loginpage</key> <string>http://island.sciencesim.com/scisim/loginscreen.php</string> - <key>helperuri</key> <string></string> - <key>password</key> <string>http://island.sciencesim.com/scisim</string> - <key>register</key> <string>http://island.sciencesim.com/scisim</string> - <key>support</key> <string>http://island.sciencesim.com/wiki</string> - <key>website</key> <string>http://island.sciencesim.com/about/</string> - <key>version</key> <string>0</string> - </map> - </array> </llsd> diff --git a/linden/indra/newview/app_settings/dictionaries/en_sl.dic b/linden/indra/newview/app_settings/dictionaries/en_sl.dic index f37b60db0..09076f788 100644 --- a/linden/indra/newview/app_settings/dictionaries/en_sl.dic +++ b/linden/indra/newview/app_settings/dictionaries/en_sl.dic @@ -1098,6 +1098,8 @@ STATUS_DIE_AT_EDGE STATUS_RETURN_AT_EDGE STATUS_CAST_SHADOWS AGENT +AGENT_BY_USERNAME +AGENT_BY_LEGACY_NAME ACTIVE PASSIVE SCRIPTED diff --git a/linden/indra/newview/app_settings/keywords.ini b/linden/indra/newview/app_settings/keywords.ini index 8e303dc22..36a4cdc30 100644 --- a/linden/indra/newview/app_settings/keywords.ini +++ b/linden/indra/newview/app_settings/keywords.ini @@ -66,7 +66,9 @@ STATUS_BLOCK_GRAB Passed in the llSetStatus library function. If TRUE, object c STATUS_DIE_AT_EDGE Passed in the llSetStatus library function. If TRUE, objects that reach the edge of the world just die:rather than teleporting back to the owner STATUS_RETURN_AT_EDGE Passed in the llSetStatus library function. If TRUE, script rezzed objects that reach the edge of the world:are returned rather than killed:STATUS_RETURN_AT_EDGE trumps STATUS_DIE_AT_EDGE if both are set STATUS_CAST_SHADOWS Passed in the llSetStatus library function. If TRUE, object casts shadows on other objects -AGENT Passed in llSensor library function to look for other Agents +AGENT Passed in llSensor library function to look for other Agents; DEPRECATED: Use AGENT_BY_LEGACY_NAME +AGENT_BY_USERNAME Passed in llSensor library function to look for other Agents by username +AGENT_BY_LEGACY_NAME Passed in llSensor library function to look for other Agents by legacy name ACTIVE Passed in llSensor library function to look for moving objects PASSIVE Passed in llSensor library function to look for objects that aren't moving SCRIPTED Passed in llSensor library function to look for scripted objects diff --git a/linden/indra/newview/app_settings/logcontrol.xml b/linden/indra/newview/app_settings/logcontrol.xml index 682bf6492..c94fc5143 100644 --- a/linden/indra/newview/app_settings/logcontrol.xml +++ b/linden/indra/newview/app_settings/logcontrol.xml @@ -66,6 +66,7 @@ <!--<string>Messaging</string>--> <!--<string>Notifications</string>--> + <!--<string>Plugin</string>--> <!--<string>Radar</string>--> <!--<string>ShaderLoading</string>--> diff --git a/linden/indra/newview/app_settings/settings.xml b/linden/indra/newview/app_settings/settings.xml index 8c280d405..11ae20afa 100644 --- a/linden/indra/newview/app_settings/settings.xml +++ b/linden/indra/newview/app_settings/settings.xml @@ -1,12 +1,60 @@ <?xml version="1.0" ?> <llsd> <map> - + +<!-- for Aurora Sim --> + + <key>TimeOffset</key> + <map> + <key>Comment</key> + <string>difference in hours to UTC time</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>UseTimeOffset</key> + <map> + <key>Comment</key> + <string>Use debug setting TimeOffset</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>TimeOffsetDST</key> + <map> + <key>Comment</key> + <string>TimeOffset has Day Light Savings</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <!-- Imprudence-specific settings --> + <key>AllowEditingOfTrees</key> + <map> + <key>Comment</key> + <string>Allow editing of trees and grass</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <!-- begin name highlighting --> - <key>nick01</key> + <key>HighlightNickname01</key> <map> <key>Comment</key> <string>First Nickname for Chat Highlight</string> @@ -17,7 +65,7 @@ <key>Value</key> <string></string> </map> - <key>nick02</key> + <key>HighlightNickname02</key> <map> <key>Comment</key> <string>Second Nickname for Chat Highlight</string> @@ -28,7 +76,7 @@ <key>Value</key> <string></string> </map> - <key>nick03</key> + <key>HighlightNickname03</key> <map> <key>Comment</key> <string>Third Nickname for Chat Highlight</string> @@ -195,6 +243,94 @@ <key>Value</key> <real>20</real> </map> + <key>ClassicCloudHeight</key> + <map> + <key>Comment</key> + <string>Height for classic particle clouds</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>192</integer> + </map> + <key>ClassicCloudRange</key> + <map> + <key>Comment</key> + <string>Height range for classic particle clouds</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>48</integer> + </map> + <key>CloudCountMax</key> + <map> + <key>Comment</key> + <string>Max amount of particle clouds</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>20</integer> + </map> + <key>CloudVelocityScale</key> + <map> + <key>Comment</key> + <string>Particle cloud velocity</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>CloudDecayRate</key> + <map> + <key>Comment</key> + <string>Particle cloud decay rate</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>-5</integer> + </map> + <key>CloudGrowRate</key> + <map> + <key>Comment</key> + <string>Particle cloud grow rate</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>5</integer> + </map> + <key>CloudUpdateRate</key> + <map> + <key>Comment</key> + <string>Particle cloud update rate</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>CloudDensity</key> + <map> + <key>Comment</key> + <string>Particle cloud density</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>25</integer> + </map> <key>ConnectingToRegionTimeout</key> <map> <key>Comment</key> @@ -228,6 +364,17 @@ <key>Value</key> <integer>3</integer> </map> + <key>DisableInternalFlyUpAnimation</key> + <map> + <key>Comment</key> + <string>Disables the internal hover up animation (on your local computer only). Enable if you use an AO and wear hand attachments like rings, prim nails etc. that often loose their correct position while flying.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>DisableLoginLogoutScreens</key> <map> <key>Comment</key> @@ -396,6 +543,39 @@ <key>Value</key> <string>DroidSans</string> </map> + <key>FontSizeMultiplier</key> + <map> + <key>Comment</key> + <string>Multiply all font sizes by this amount. Requires viewer restart.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <string>1.0</string> + </map> + <key>FontSizeRounding</key> + <map> + <key>Comment</key> + <string>Round all font sizes to integer values, to potentially reduce font blurriness. The rounding occurs after FontSizeMultiplier is applied. Requires viewer restart.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>GridUpdateList</key> + <map> + <key>Comment</key> + <string>Location to download default grid options.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>http://ansset/libcw/default_grids.xml</string> + </map> <key>GoAction</key> <map> <key>Comment</key> @@ -478,11 +658,11 @@ <key>Comment</key> <string>Allow LightShare (Windlight settings broadcast from the region): Never (0), Ask (1), or Always (2).</string> <key>Persist</key> - <integer>1</integer> + <integer>0</integer> <key>Type</key> <string>U32</string> <key>Value</key> - <integer>0</integer> + <integer>2</integer> </map> <key>LightShareIgnoreTimer</key> <map> @@ -1062,6 +1242,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>UseLocalChatWithBubbles</key> + <map> + <key>Comment</key> + <string>Should local chat still appear even when using chat bubbles?</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>UseUTCTime</key> <map> <key>Comment</key> @@ -2398,11 +2589,11 @@ <key>Comment</key> <string>Fly by holding jump key or using "Fly" command (FALSE = fly by using "Fly" command only)</string> <key>Persist</key> - <integer>1</integer> + <integer>0</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>1</integer> + <integer>0</integer> </map> <key>AvatarAxisDeadZone0</key> <map> @@ -2661,6 +2852,39 @@ <key>Value</key> <integer>0</integer> </map> + <key>BrowserCookiesEnabled</key> + <map> + <key>Comment</key> + <string>Accept cookies from Web sites?</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>BrowserJavascriptEnabled</key> + <map> + <key>Comment</key> + <string>Enable Javascript in the built-in Web browser?</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>BrowserPluginsEnabled</key> + <map> + <key>Comment</key> + <string>Enable Web plugins in the built-in Web browser?</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>BrowserProxyAddress</key> <map> <key>Comment</key> @@ -2881,39 +3105,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>BulkChangeIncludeAnimations</key> - <map> - <key>Comment</key> - <string>Bulk permission changes affect animations</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>BulkChangeIncludeAnimations</key> - <map> - <key>Comment</key> - <string>Bulk permission changes affect animations</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>BulkChangeIncludeAnimations</key> - <map> - <key>Comment</key> - <string>Bulk permission changes affect animations</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>BulkChangeIncludeBodyParts</key> <map> <key>Comment</key> @@ -4099,17 +4290,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>CookiesEnabled</key> - <map> - <key>Comment</key> - <string>Accept cookies from Web sites?</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>CreateToolCopyCenters</key> <map> <key>Comment</key> @@ -4209,6 +4389,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>DebugPluginDisableTimeout</key> + <map> + <key>Comment</key> + <string>Disable the code which watches for plugins that are crashed or hung</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>DebugShowColor</key> <map> <key>Comment</key> @@ -7698,7 +7889,40 @@ <key>Value</key> <integer>0</integer> </map> - <key>MemoryLogFrequency</key> + <key>MediaControlFadeTime</key> + <map> + <key>Comment</key> + <string>Amount of time (in seconds) that the media control fades</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.5</real> + </map> + <key>MediaControlTimeout</key> + <map> + <key>Comment</key> + <string>Amount of time (in seconds) for media controls to fade with no mouse activity</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>3.0</real> + </map> + <key>MediaOnAPrimUI</key> + <map> + <key>Comment</key> + <string>Whether or not to show the "link sharing" UI</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>MemoryLogFrequency</key> <map> <key>Comment</key> <string>Seconds between display of Memory in log (0 for never)</string> @@ -8465,6 +8689,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>PluginAttachDebuggerToPlugins</key> + <map> + <key>Comment</key> + <string>If true, attach a debugger session to each plugin process as it's launched.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>PrecachingDelay</key> <map> <key>Comment</key> diff --git a/linden/indra/newview/app_settings/viewerversion.xml b/linden/indra/newview/app_settings/viewerversion.xml index f50b59420..f9b0ba2b3 100644 --- a/linden/indra/newview/app_settings/viewerversion.xml +++ b/linden/indra/newview/app_settings/viewerversion.xml @@ -20,6 +20,6 @@ need to be changed manually - MC <viewer version_patch="0" /> <!--string--> - <viewer version_test="Experimental 2010.10.17" /> + <viewer version_test="Experimental 2010.11.13" /> </viewer_version> diff --git a/linden/indra/newview/chatbar_as_cmdline.cpp b/linden/indra/newview/chatbar_as_cmdline.cpp index 9359444a0..059309134 100644 --- a/linden/indra/newview/chatbar_as_cmdline.cpp +++ b/linden/indra/newview/chatbar_as_cmdline.cpp @@ -16,7 +16,7 @@ * may be used to endorse or promote products derived from this * software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY MODULAR SYSTEMS AND CONTRIBUTORS "AS IS" + * THIS SOFTWARE IS PROVIDED BY MODULAR SYSTEMS AND CONTRIBUTORS ?AS IS? * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MODULAR SYSTEMS OR CONTRIBUTORS @@ -43,7 +43,7 @@ #include "lluuid.h" #include "llviewercontrol.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include "material_codes.h" #include "llvolume.h" #include "object_flags.h" @@ -69,7 +69,7 @@ #include "llviewerparcelmgr.h" #include "llviewerparcelmedia.h" #include "llparcel.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llviewerparcelmediaautoplay.h" #include "lloverlaybar.h" #include "lggautocorrectfloater.h" diff --git a/linden/indra/newview/emeraldboobutils.cpp b/linden/indra/newview/emeraldboobutils.cpp index f68d6a7b8..f4409407f 100644 --- a/linden/indra/newview/emeraldboobutils.cpp +++ b/linden/indra/newview/emeraldboobutils.cpp @@ -1,3 +1,4 @@ +#include "linden_common.h" #include "emeraldboobutils.h" std::ostream &operator<<(std::ostream &os, const EmeraldGlobalBoobConfig &v) diff --git a/linden/indra/newview/floatercommandline.cpp b/linden/indra/newview/floatercommandline.cpp index c093a5828..6889696ca 100644 --- a/linden/indra/newview/floatercommandline.cpp +++ b/linden/indra/newview/floatercommandline.cpp @@ -32,7 +32,7 @@ #include "floatercommandline.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include "lluictrlfactory.h" #include "llviewercontrol.h" diff --git a/linden/indra/newview/floatergriddefault.cpp b/linden/indra/newview/floatergriddefault.cpp index 2c31fb66e..6a2526dbb 100644 --- a/linden/indra/newview/floatergriddefault.cpp +++ b/linden/indra/newview/floatergriddefault.cpp @@ -32,7 +32,7 @@ #include "floatergriddefault.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include "llpanellogin.h" #include "llscrolllistctrl.h" #include "lluictrlfactory.h" diff --git a/linden/indra/newview/floatergridmanager.cpp b/linden/indra/newview/floatergridmanager.cpp index 3d4b17ff4..298fe3505 100644 --- a/linden/indra/newview/floatergridmanager.cpp +++ b/linden/indra/newview/floatergridmanager.cpp @@ -17,7 +17,7 @@ #include "llmd5.h" #include "llurlsimstring.h" #include "lluictrlfactory.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include "llviewernetwork.h" #include "llpanellogin.h" diff --git a/linden/indra/newview/floaterlocalassetbrowse.cpp b/linden/indra/newview/floaterlocalassetbrowse.cpp index 991d2fd60..8ea13ccc3 100644 --- a/linden/indra/newview/floaterlocalassetbrowse.cpp +++ b/linden/indra/newview/floaterlocalassetbrowse.cpp @@ -53,7 +53,7 @@ this feature is still a work in progress. /* misc headers */ #include <time.h> #include <ctime> -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include "llviewerimagelist.h" #include "llviewerobjectlist.h" #include "llfilepicker.h" diff --git a/linden/indra/newview/floatervoicelicense.cpp b/linden/indra/newview/floatervoicelicense.cpp index 840a9e6aa..e8cd4f38a 100644 --- a/linden/indra/newview/floatervoicelicense.cpp +++ b/linden/indra/newview/floatervoicelicense.cpp @@ -122,7 +122,7 @@ BOOL FloaterVoiceLicense::postBuild() LLTextEditor *editor = getChild<LLTextEditor>("license_text"); editor->setVisible( FALSE ); - LLWebBrowserCtrl* web_browser = getChild<LLWebBrowserCtrl>("license_html"); + LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("license_html"); if ( web_browser ) { // start to observe it so we see navigate complete events @@ -137,7 +137,7 @@ BOOL FloaterVoiceLicense::postBuild() void FloaterVoiceLicense::setSiteIsAlive( bool alive ) { - LLWebBrowserCtrl* web_browser = getChild<LLWebBrowserCtrl>("license_html"); + LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("license_html"); // if the contents of the site was retrieved if ( alive ) { @@ -158,12 +158,6 @@ void FloaterVoiceLicense::setSiteIsAlive( bool alive ) FloaterVoiceLicense::~FloaterVoiceLicense() { - // stop observing events - LLWebBrowserCtrl* web_browser = getChild<LLWebBrowserCtrl>("license_html"); - if ( web_browser ) - { - web_browser->remObserver( this ); - } // tell the responder we're not here anymore if ( gResponsePtr ) @@ -224,14 +218,17 @@ void FloaterVoiceLicense::onCancel( void* userdata ) } //virtual -void FloaterVoiceLicense::onNavigateComplete( const EventType& eventIn ) +void FloaterVoiceLicense::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event) { - // skip past the loading screen navigate complete - if ( ++mLoadCompleteCount == 2 ) + if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) { - llinfos << "NAVIGATE COMPLETE" << llendl; - // enable Agree to License radio button now that page has loaded - LLCheckBoxCtrl * license_agreement = getChild<LLCheckBoxCtrl>("agree_chk"); - license_agreement->setEnabled( true ); + // skip past the loading screen navigate complete + if ( ++mLoadCompleteCount == 2 ) + { + llinfos << "NAVIGATE COMPLETE" << llendl; + // enable Agree to License radio button now that page has loaded + LLCheckBoxCtrl * license_agreement = getChild<LLCheckBoxCtrl>("agree_chk"); + license_agreement->setEnabled( true ); + } } } diff --git a/linden/indra/newview/floatervoicelicense.h b/linden/indra/newview/floatervoicelicense.h index 4130d2287..30dbb2fa3 100644 --- a/linden/indra/newview/floatervoicelicense.h +++ b/linden/indra/newview/floatervoicelicense.h @@ -35,7 +35,7 @@ #include "llmodaldialog.h" #include "llassetstorage.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" class LLButton; class LLRadioGroup; @@ -45,7 +45,7 @@ class LLUUID; class FloaterVoiceLicense : public LLModalDialog, - public LLWebBrowserCtrlObserver, + public LLViewerMediaObserver, public LLFloaterSingleton<FloaterVoiceLicense> { public: @@ -62,7 +62,8 @@ class FloaterVoiceLicense : void setSiteIsAlive( bool alive ); - virtual void onNavigateComplete( const EventType& eventIn ); + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); private: int mWebBrowserWindowId; diff --git a/linden/indra/newview/hippoLimits.cpp b/linden/indra/newview/hippoLimits.cpp deleted file mode 100644 index 92e2ed32e..000000000 --- a/linden/indra/newview/hippoLimits.cpp +++ /dev/null @@ -1,87 +0,0 @@ - - -#include "llviewerprecompiledheaders.h" - -#include "hippoLimits.h" - -#include "hippoGridManager.h" -#include "llviewercontrol.h" - -#include <llerror.h> - - -HippoLimits *gHippoLimits = 0; - - -HippoLimits::HippoLimits() -: - mMaxAgentGroups(100), - mMaxHeight(10000.0f), - mMinHoleSize(0.05f), - mMaxHollow(0.95f), - mMinPrimScale(0.001f), - mMaxPrimScale(256.0f), - mMaxLinkedPrims(-1) -{ - setLimits(); -} - - -void HippoLimits::setLimits() -{ - if (gHippoGridManager->getConnectedGrid()->getPlatform() == HippoGridInfo::PLATFORM_SECONDLIFE) - { - setSecondLifeLimits(); - } - else - { - setOpenSimLimits(); - } -} - - -void HippoLimits::setOpenSimLimits() -{ - mMaxAgentGroups = gHippoGridManager->getConnectedGrid()->getMaxAgentGroups(); - if (mMaxAgentGroups < 0) mMaxAgentGroups = 50; - mMaxPrimScale = 256.0f; - mMinPrimScale = 0.001f; - mMaxHeight = 10000.0f; - mMaxLinkedPrims = -1; - - if (gHippoGridManager->getConnectedGrid()->isRenderCompat()) { - llinfos << "Using rendering compatible OpenSim limits" << llendl; - mMinHoleSize = 0.05f; - mMaxHollow = 0.95f; - } - else - { - llinfos << "Using Hippo OpenSim limits" << llendl; - mMinHoleSize = 0.01f; - mMaxHollow = 0.99f; - } -} - -void HippoLimits::setSecondLifeLimits() -{ - llinfos << "Using Second Life limits" << llendl; - mMaxAgentGroups = 25; - mMaxPrimScale = 10.0f; - mMinPrimScale = 0.01f; - mMaxHeight = 4096.0f; - mMinHoleSize = 0.05f; - mMaxHollow = 0.95f; - mMaxLinkedPrims = 255; -} - -F32 HippoLimits::getMaxPrimScale() const -{ - if (gSavedSettings.getBOOL("DisableMaxBuildConstraints")) - { - return FLT_MAX; - } - else - { - return mMaxPrimScale; - } -} diff --git a/linden/indra/newview/hippoLimits.h b/linden/indra/newview/hippoLimits.h deleted file mode 100644 index a5fe3518c..000000000 --- a/linden/indra/newview/hippoLimits.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __HIPPO_LIMITS_H__ -#define __HIPPO_LIMITS_H__ - - -class HippoLimits -{ -public: - HippoLimits(); - - const S32& getMaxAgentGroups() const { return mMaxAgentGroups; } - const F32& getMaxHeight() const { return mMaxHeight; } - const F32& getMinHoleSize() const { return mMinHoleSize; } - const F32& getMaxHollow() const { return mMaxHollow; } - const F32& getMinPrimScale() const { return mMinPrimScale; } - const S32& getMaxLinkedPrims() const { return mMaxLinkedPrims; } - - // Returns the max prim size we can use on a grid - F32 getMaxPrimScale() const; - - void setLimits(); - - S32 mMaxAgentGroups; - - F32 mMaxHeight; - F32 mMinHoleSize; - F32 mMaxHollow; - F32 mMaxPrimScale; - F32 mMinPrimScale; - S32 mMaxLinkedPrims; - -private: - void setOpenSimLimits(); - void setSecondLifeLimits(); -}; - - -extern HippoLimits* gHippoLimits; - - -#endif diff --git a/linden/indra/newview/hippoGridManager.cpp b/linden/indra/newview/hippogridmanager.cpp similarity index 99% rename from linden/indra/newview/hippoGridManager.cpp rename to linden/indra/newview/hippogridmanager.cpp index 5a229fda7..d56214cc0 100644 --- a/linden/indra/newview/hippoGridManager.cpp +++ b/linden/indra/newview/hippogridmanager.cpp @@ -2,7 +2,7 @@ #include "llviewerprecompiledheaders.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include <cctype> @@ -17,7 +17,7 @@ #include "llviewercontrol.h" #include "llweb.h" -#include "hippoRestRequest.h" +#include "hipporestrequest.h" // ******************************************************************** @@ -799,7 +799,7 @@ void HippoGridManager::loadFromFile() parseFile(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "default_grids.xml"), !mGridInfo.empty()); // merge grid info from web site, if newer. Force load, if list of grids is empty. if (gSavedSettings.getBOOL("CheckForGridUpdates")) - parseUrl("http://imprudenceviewer.org/app/grids/", !mGridInfo.empty()); + parseUrl(gSavedSettings.getString("GridUpdateList"), !mGridInfo.empty()); std::string last_grid = gSavedSettings.getString("LastSelectedGrid"); if (last_grid.empty()) last_grid = gSavedSettings.getString("DefaultGrid"); @@ -808,7 +808,7 @@ void HippoGridManager::loadFromFile() } -void HippoGridManager::parseUrl(const char* url, bool mergeIfNewer) +void HippoGridManager::parseUrl(const std::string url, bool mergeIfNewer) { llinfos << "Loading grid info from '" << url << "'." << llendl; diff --git a/linden/indra/newview/hippoGridManager.h b/linden/indra/newview/hippogridmanager.h similarity index 98% rename from linden/indra/newview/hippoGridManager.h rename to linden/indra/newview/hippogridmanager.h index bc19ff8af..8429dbaf6 100644 --- a/linden/indra/newview/hippoGridManager.h +++ b/linden/indra/newview/hippogridmanager.h @@ -172,7 +172,7 @@ class HippoGridManager void cleanup(); void loadFromFile(); void parseFile(const std::string& fileName, bool mergeIfNewer); - void parseUrl(const char* url, bool mergeIfNewer); + void parseUrl(const std::string url, bool mergeIfNewer); void parseData(LLSD &gridInfo, bool mergeIfNewer); }; diff --git a/linden/indra/newview/hippolimits.cpp b/linden/indra/newview/hippolimits.cpp new file mode 100644 index 000000000..3368ba4c4 --- /dev/null +++ b/linden/indra/newview/hippolimits.cpp @@ -0,0 +1,225 @@ + + +#include "llviewerprecompiledheaders.h" + +#include "hippolimits.h" + +#include "hippogridmanager.h" +#include "llviewercontrol.h" + +#include <llerror.h> + + +HippoLimits *gHippoLimits = 0; + + +HippoLimits::HippoLimits() +: + mMaxAgentGroups(100), + mMaxHeight(10000.0f), + mMinHoleSize(0.05f), + mMaxHollow(0.95f), + mMinPrimScale(0.001f), + mMaxPrimScale(256.0f), + mMaxLinkedPrims(-1), + mMaxDragDistance(0.f) +{ + setLimits(); +} + + +void HippoLimits::setLimits() +{ + if (gHippoGridManager->getConnectedGrid()->getPlatform() == HippoGridInfo::PLATFORM_SECONDLIFE) + { + setSecondLifeLimits(); + } + else + { + setOpenSimLimits(); + } +} + + +void HippoLimits::setOpenSimLimits() +{ + mMaxAgentGroups = gHippoGridManager->getConnectedGrid()->getMaxAgentGroups(); + + if (mMaxAgentGroups < 0) + mMaxAgentGroups = 50; + + mMaxPrimScale = 256.0f; + mMinPrimScale = 0.001f; + mMinPrimXPos = 0; + mMinPrimYPos = 0; + mMinPrimZPos = 0; + mMaxPrimXPos = F32_MAX; + mMaxPrimYPos = F32_MAX; + mMaxPrimZPos = F32_MAX; + mMaxHeight = 10000.0f; + mMaxLinkedPrims = -1; + mMaxPhysLinkedPrims = -1; + mAllowParcelWindLight = TRUE; + mAllowMinimap = TRUE; + mMaxInventoryItemsTransfer = -1; + mRenderName = 2; + mAllowPhysicalPrims = TRUE; + skyUseClassicClouds = TRUE; + mEnableTeenMode = FALSE; + mEnforceMaxBuild = FALSE; + mRenderWater = TRUE; + + if (gHippoGridManager->getConnectedGrid()->isRenderCompat()) { + llinfos << "Using rendering compatible OpenSim limits" << llendl; + mMinHoleSize = 0.05f; + mMaxHollow = 0.95f; + } + else + { + llinfos << "Using Hippo OpenSim limits" << llendl; + mMinHoleSize = 0.01f; + mMaxHollow = 0.99f; + } +} + +void HippoLimits::setSecondLifeLimits() +{ + llinfos << "Using Second Life limits" << llendl; + mMaxAgentGroups = 25; + mMaxPrimScale = 10.0f; + mMinPrimScale = 0.01f; + mMaxHeight = 4096.0f; + mMinHoleSize = 0.05f; + mMaxHollow = 0.95f; + mMaxLinkedPrims = 255; + mMaxPhysLinkedPrims = 32; + mMinPrimXPos = 0; + mMinPrimYPos = 0; + mMinPrimZPos = 0; + mMaxPrimXPos = 256; + mMaxPrimYPos = 256; + mMaxPrimZPos = 4096; + mAllowParcelWindLight = FALSE; + mAllowMinimap = TRUE; + mMaxInventoryItemsTransfer = 42; + mRenderName = 2; + mAllowPhysicalPrims = TRUE; + skyUseClassicClouds = TRUE; + mEnableTeenMode = FALSE; + mEnforceMaxBuild = FALSE; + mRenderWater = TRUE; +} + +F32 HippoLimits::getMaxPrimScale() const +{ + if (gSavedSettings.getBOOL("DisableMaxBuildConstraints") && !mEnforceMaxBuild) + { + return FLT_MAX; + } + else + { + return mMaxPrimScale; + } +} + +F32 HippoLimits::getMinPrimScale() const +{ + if (gSavedSettings.getBOOL("DisableMaxBuildConstraints") && !mEnforceMaxBuild) + { + return 0; + } + else + { + return mMinPrimScale; + } +} + +F32 HippoLimits::getMaxPrimXPos() const +{ + if (gSavedSettings.getBOOL("DisableMaxBuildConstraints") && !mEnforceMaxBuild) + { + return FLT_MAX; + } + else + { + return mMaxPrimXPos; + } +} + +F32 HippoLimits::getMaxPrimYPos() const +{ + if (gSavedSettings.getBOOL("DisableMaxBuildConstraints") && !mEnforceMaxBuild) + { + return FLT_MAX; + } + else + { + return mMaxPrimYPos; + } +} + +F32 HippoLimits::getMaxPrimZPos() const +{ + if (gSavedSettings.getBOOL("DisableMaxBuildConstraints") && !mEnforceMaxBuild) + { + return FLT_MAX; + } + else + { + return mMaxPrimZPos; + } +} + +F32 HippoLimits::getMinPrimXPos() const +{ + if (gSavedSettings.getBOOL("DisableMaxBuildConstraints") && !mEnforceMaxBuild) + { + return FLT_MIN; + } + else + { + return mMinPrimXPos; + } +} + +F32 HippoLimits::getMinPrimYPos() const +{ + if (gSavedSettings.getBOOL("DisableMaxBuildConstraints") && !mEnforceMaxBuild) + { + return FLT_MIN; + } + else + { + return mMinPrimYPos; + } +} + +F32 HippoLimits::getMinPrimZPos() const +{ + if (gSavedSettings.getBOOL("DisableMaxBuildConstraints") && !mEnforceMaxBuild) + { + return FLT_MIN; + } + else + { + return mMinPrimZPos; + } +} + +F32 HippoLimits::getMaxDragDistance() const +{ + if (mMaxDragDistance == 0.f) + { + return FLT_MAX; + } + else + { + F32 max_drag_distance = gSavedSettings.getBOOL("LimitDragDistance") ? gSavedSettings.getF32("MaxDragDistance") : FLT_MAX; + + if(max_drag_distance > mMaxDragDistance) //Chose the more restrictive + { + max_drag_distance = mMaxDragDistance; + } + return max_drag_distance; + } +} \ No newline at end of file diff --git a/linden/indra/newview/hippolimits.h b/linden/indra/newview/hippolimits.h new file mode 100644 index 000000000..7792a2c30 --- /dev/null +++ b/linden/indra/newview/hippolimits.h @@ -0,0 +1,72 @@ +#ifndef __HIPPO_LIMITS_H__ +#define __HIPPO_LIMITS_H__ + + +class HippoLimits +{ +public: + HippoLimits(); + + const S32& getMaxAgentGroups() const { return mMaxAgentGroups; } + const F32& getMaxHeight() const { return mMaxHeight; } + const F32& getMinHoleSize() const { return mMinHoleSize; } + const F32& getMaxHollow() const { return mMaxHollow; } + const S32& getMaxLinkedPrims() const { return mMaxLinkedPrims; } + const S32& getMaxPhysLinkedPrims() const { return mMaxPhysLinkedPrims; } + const F32& getMaxInventoryItemsTransfer() const { return mMaxInventoryItemsTransfer; } + + + // Returns the max prim size we can use on a grid + F32 getMinPrimScale() const; + F32 getMaxPrimScale() const; + + F32 getMaxDragDistance() const; + + F32 getMinPrimXPos() const; + F32 getMinPrimYPos() const; + F32 getMinPrimZPos() const; + F32 getMaxPrimXPos() const; + F32 getMaxPrimYPos() const; + F32 getMaxPrimZPos() const; + + void setLimits(); + + S32 mMaxAgentGroups; + + F32 mMaxHeight; + F32 mMinHoleSize; + F32 mMaxHollow; + F32 mMaxPrimScale; + F32 mMinPrimScale; + S32 mMaxLinkedPrims; + S32 mMaxPhysLinkedPrims; + F32 mMaxPrimXPos; + F32 mMaxPrimYPos; + F32 mMaxPrimZPos; + F32 mMinPrimXPos; + F32 mMinPrimYPos; + F32 mMinPrimZPos; + + S32 mRenderName; + + F32 mMaxInventoryItemsTransfer; + F32 mMaxDragDistance; + + BOOL skyUseClassicClouds; + BOOL mAllowParcelWindLight; + BOOL mAllowMinimap; + BOOL mAllowPhysicalPrims; + BOOL mEnableTeenMode; + BOOL mEnforceMaxBuild; + BOOL mRenderWater; + +private: + void setOpenSimLimits(); + void setSecondLifeLimits(); +}; + + +extern HippoLimits* gHippoLimits; + + +#endif diff --git a/linden/indra/newview/hippoRestRequest.cpp b/linden/indra/newview/hipporestrequest.cpp similarity index 99% rename from linden/indra/newview/hippoRestRequest.cpp rename to linden/indra/newview/hipporestrequest.cpp index ed159074d..9d24aed4b 100644 --- a/linden/indra/newview/hippoRestRequest.cpp +++ b/linden/indra/newview/hipporestrequest.cpp @@ -2,7 +2,7 @@ #include "llviewerprecompiledheaders.h" -#include "hippoRestRequest.h" +#include "hipporestrequest.h" #ifndef CURL_STATICLIB #define CURL_STATICLIB 1 diff --git a/linden/indra/newview/hippoRestRequest.h b/linden/indra/newview/hipporestrequest.h similarity index 100% rename from linden/indra/newview/hippoRestRequest.h rename to linden/indra/newview/hipporestrequest.h diff --git a/linden/indra/newview/hippoUpdate.cpp b/linden/indra/newview/hippoupdate.cpp similarity index 99% rename from linden/indra/newview/hippoUpdate.cpp rename to linden/indra/newview/hippoupdate.cpp index f6947ade4..192e3d74a 100644 --- a/linden/indra/newview/hippoUpdate.cpp +++ b/linden/indra/newview/hippoupdate.cpp @@ -1,5 +1,5 @@ -#include "hippoUpdate.h" +#include "hippoupdate.h" #include <cstdio> #include <list> diff --git a/linden/indra/newview/hippoUpdate.h b/linden/indra/newview/hippoupdate.h similarity index 100% rename from linden/indra/newview/hippoUpdate.h rename to linden/indra/newview/hippoupdate.h diff --git a/linden/indra/newview/impprefsfonts.cpp b/linden/indra/newview/impprefsfonts.cpp index 3ce71ebb5..a4dcd345d 100644 --- a/linden/indra/newview/impprefsfonts.cpp +++ b/linden/indra/newview/impprefsfonts.cpp @@ -29,7 +29,9 @@ #include "llviewerprecompiledheaders.h" #include "impprefsfonts.h" +#include "llcheckboxctrl.h" #include "llradiogroup.h" +#include "llspinctrl.h" #include "lluictrlfactory.h" #include "llviewercontrol.h" @@ -61,24 +63,64 @@ void ImpPrefsFonts::refresh() { fonts->setValue( gSavedSettings.getString("FontChoice") ); } + + LLSpinCtrl* font_mult = getChild<LLSpinCtrl>("font_mult"); + if (font_mult) + { + font_mult->setValue( gSavedSettings.getF32("FontSizeMultiplier") ); + } + + LLCheckBoxCtrl* font_round = getChild<LLCheckBoxCtrl>("font_round"); + if (font_round) + { + font_round->setValue( gSavedSettings.getBOOL("FontSizeRounding") ); + } } void ImpPrefsFonts::apply() { - LLRadioGroup* fonts = getChild<LLRadioGroup>("fonts"); + bool changed = false; + LLRadioGroup* fonts = getChild<LLRadioGroup>("fonts"); if (fonts) { std::string font_choice = fonts->getValue().asString(); - if (font_choice != gSavedSettings.getString("FontChoice") && !font_choice.empty()) { gSavedSettings.setString("FontChoice", font_choice); - LLNotifications::instance().add("ChangeFont"); - refresh(); + changed = true; } } + + LLSpinCtrl* font_mult = getChild<LLSpinCtrl>("font_mult"); + if (font_mult) + { + F32 mult = font_mult->getValue().asReal(); + if (mult != gSavedSettings.getF32("FontSizeMultiplier")) + { + gSavedSettings.setF32("FontSizeMultiplier", mult); + changed = true; + } + } + + LLCheckBoxCtrl* font_round = getChild<LLCheckBoxCtrl>("font_round"); + if (font_round) + { + BOOL round = font_round->getValue().asBoolean(); + if (round != gSavedSettings.getBOOL("FontSizeRounding")) + { + gSavedSettings.setBOOL("FontSizeRounding", round); + changed = true; + } + } + + if (changed) + { + refresh(); + LLNotifications::instance().add("ChangeFont"); + } + } void ImpPrefsFonts::cancel() diff --git a/linden/indra/newview/jcfloaterareasearch.cpp b/linden/indra/newview/jcfloaterareasearch.cpp index ed00447df..0918431ba 100644 --- a/linden/indra/newview/jcfloaterareasearch.cpp +++ b/linden/indra/newview/jcfloaterareasearch.cpp @@ -38,7 +38,14 @@ #include "llscrolllistctrl.h" #include "llagent.h" + +#include "llfloatertools.h" +#include "llmenugl.h" +#include "llselectmgr.h" +#include "lltoolcomp.h" +#include "lltoolmgr.h" #include "lltracker.h" +#include "llviewerjoystick.h" #include "llviewerobjectlist.h" #include "llviewercontrol.h" #include "jcfloaterareasearch.h" @@ -63,6 +70,19 @@ mResultList(0) llassert_always(sInstance == NULL); sInstance = this; mLastUpdateTimer.reset(); + + + // Register event listeners for popup menu + mPopupMenuHandler = new PopupMenuHandler(this); + mPopupMenuHandler->registerListener(this, "Popup.HandleMenu"); + + LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_areasearch.xml", this); + if (!menu) + { + menu = new LLMenuGL(LLStringUtil::null); + } + menu->setVisible(FALSE); + mPopupMenuHandle = menu->getHandle(); } JCFloaterAreaSearch::~JCFloaterAreaSearch() @@ -90,6 +110,7 @@ BOOL JCFloaterAreaSearch::postBuild() mResultList = getChild<LLScrollListCtrl>("result_list"); mResultList->setCallbackUserData(this); mResultList->setDoubleClickCallback(onDoubleClick); + mResultList->setRightMouseDownCallback(onRightMouseDown); mResultList->sortByColumn("Name", TRUE); mCounterText = getChild<LLTextBox>("counter"); @@ -159,6 +180,102 @@ void JCFloaterAreaSearch::onDoubleClick(void *userdata) } } +//static +void JCFloaterAreaSearch::onRightMouseDown(S32 x, S32 y, void *userdata) +{ + JCFloaterAreaSearch* self = (JCFloaterAreaSearch*)userdata; + + self->setFocus( TRUE ); + LLMenuGL* menu = (LLMenuGL*)self->mPopupMenuHandle.get(); + if(menu) + { + if(menu->getVisible()) + { + menu->setVisible(FALSE); + } + else + { + LLScrollListItem *item = self->mResultList->getFirstSelected(); + if (item) + { + self->mSelectedItem = item; + menu->setVisible(TRUE); + menu->setFocus(TRUE); + menu->arrange(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(self, menu, x, y+50); + } + else + { + self->mSelectedItem = NULL; + } + } + } + +} + +JCFloaterAreaSearch::PopupMenuHandler::PopupMenuHandler(const JCFloaterAreaSearch* instance) + : mInstance(instance) +{ + +} + +// static +bool JCFloaterAreaSearch::PopupMenuHandler::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) +{ + std::string command = userdata.asString(); + JCFloaterAreaSearch* self = (JCFloaterAreaSearch*)mInstance; + + if (self && self->mSelectedItem && !command.empty()) + { + LLUUID object_id = self->mSelectedItem->getUUID(); + LLViewerObject* object = gObjectList.findObject(object_id); + + if (object && !object->isAvatar()) + { + + + if ("teleport" == command) + { + LLVector3d pos = object->getPositionGlobal(); + gAgent.teleportViaLocation(pos); + + } + else + { + if ("cam" || "edit" == command) + { + + gAgent.setFocusOnAvatar(FALSE, FALSE); + gAgent.changeCameraToThirdPerson(); + gAgent.setFocusGlobal(object->getPositionGlobal(), object_id); + gAgent.setCameraPosAndFocusGlobal(object->getPositionGlobal() + + LLVector3d(3.5,1.35,0.75) * object->getRotation(), + object->getPositionGlobal(), + object_id ); + if ("edit" == command) + { + if(!object->isSelected()) + { + LLSelectMgr::getInstance()->deselectAll(); + LLSelectMgr::getInstance()->selectObjectAndFamily(object); + } + + gFloaterTools->open(); + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() ); + + LLViewerJoystick::getInstance()->moveObjects(true); + LLViewerJoystick::getInstance()->setNeedsReset(true); + } + } + } + } + } + + return true; +} + // static void JCFloaterAreaSearch::cancel(void* data) { diff --git a/linden/indra/newview/jcfloaterareasearch.h b/linden/indra/newview/jcfloaterareasearch.h index 151203052..5bceb5988 100644 --- a/linden/indra/newview/jcfloaterareasearch.h +++ b/linden/indra/newview/jcfloaterareasearch.h @@ -35,9 +35,11 @@ #include "lluuid.h" #include "llstring.h" #include "llframetimer.h" +#include "llmemberlistener.h" class LLTextBox; class LLScrollListCtrl; +class LLScrollListItem; class LLViewerRegion; struct AObjectDetails @@ -71,6 +73,7 @@ class JCFloaterAreaSearch : public LLFloater static void onCommitLine(LLLineEditor* line, void* user_data); static void requestIfNeeded(LLViewerObject *objectp); static void onDoubleClick(void *userdata); + static void onRightMouseDown(S32 x, S32 y, void *userdata); enum OBJECT_COLUMN_ORDER { @@ -86,6 +89,7 @@ class JCFloaterAreaSearch : public LLFloater LLTextBox* mCounterText; LLScrollListCtrl* mResultList; + LLScrollListItem* mSelectedItem; LLFrameTimer mLastUpdateTimer; static std::map<LLUUID, AObjectDetails> sObjectDetails; @@ -96,4 +100,17 @@ class JCFloaterAreaSearch : public LLFloater static std::string sSearchedGroup; static LLViewerRegion* sLastRegion; + + LLHandle<LLView> mPopupMenuHandle; + + class PopupMenuHandler : public LLMemberListener<JCFloaterAreaSearch> + { + public: PopupMenuHandler(const JCFloaterAreaSearch* instance); + + /*virtual*/ bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata); + + const JCFloaterAreaSearch* mInstance; + }; + + class PopupMenuHandler* mPopupMenuHandler; }; diff --git a/linden/indra/newview/kowopenregionsettings.cpp b/linden/indra/newview/kowopenregionsettings.cpp index f568473aa..8aac87cac 100644 --- a/linden/indra/newview/kowopenregionsettings.cpp +++ b/linden/indra/newview/kowopenregionsettings.cpp @@ -27,9 +27,15 @@ #include "llviewerprecompiledheaders.h" #include "llhttpnode.h" -#include "hippoLimits.h" +#include "hippolimits.h" #include "llfloatertools.h" #include "llviewercontrol.h" +#include "llagent.h" +#include "llsurface.h" +#include "llviewerregion.h" +#include "llviewerobject.h" +#include "llfloaterregioninfo.h" +#include "llfloaterworldmap.h" //DEBUG includes //#include "llsdserialize.h" //LLSDNotationStreamer - for dumping LLSD to string @@ -41,7 +47,7 @@ class OpenRegionInfoUpdate : public LLHTTPNode const LLSD& context, const LLSD& input) const { - if (!input.isMap() || !input.has("body")) + if (!input || !context || !input.isMap() || !input.has("body")) { llinfos << "malformed OpenRegionInfo update!" << llendl; return; @@ -62,19 +68,24 @@ class OpenRegionInfoUpdate : public LLHTTPNode if ( body.has("AllowMinimap") ) { - //IMPLEMENT ME + gHippoLimits->mAllowMinimap = body["AllowMinimap"].asInteger() == 1; } if ( body.has("AllowPhysicalPrims") ) { - //IMPLEMENT ME + gHippoLimits->mAllowPhysicalPrims = body["AllowPhysicalPrims"].asInteger() == 1; + limitschanged = TRUE; } if ( body.has("DrawDistance") ) { - //IMPLEMENT ME + F32 distance = body["DrawDistance"].asReal(); + if (distance > 0) + { + gAgent.mDrawDistance = distance; + } } if ( body.has("ForceDrawDistance") ) { - //IMPLEMENT ME + gAgent.mLockedDrawDistance = body["ForceDrawDistance"].asInteger() == 1; } if ( body.has("LSLFunctions") ) { @@ -82,19 +93,23 @@ class OpenRegionInfoUpdate : public LLHTTPNode } if ( body.has("MaxDragDistance") ) { - //IMPLEMENT ME + gHippoLimits->mMaxDragDistance = body["MaxDragDistance"].asReal(); } if ( body.has("MinHoleSize") ) { + //Note: does NOT update correctly gHippoLimits->mMinHoleSize = body["MinHoleSize"].asReal(); + limitschanged = TRUE; } if ( body.has("MaxHollowSize") ) { + //Note: does NOT update correctly gHippoLimits->mMaxHollow = body["MaxHollowSize"].asReal(); + limitschanged = TRUE; } if ( body.has("MaxInventoryItemsTransfer") ) { - //IMPLEMENT ME + gHippoLimits->mMaxInventoryItemsTransfer = body["MaxInventoryItemsTransfer"].asReal(); } if ( body.has("MaxLinkCount") ) { @@ -102,22 +117,28 @@ class OpenRegionInfoUpdate : public LLHTTPNode } if ( body.has("MaxLinkCountPhys") ) { - //IMPLEMENT ME + gHippoLimits->mMaxPhysLinkedPrims = body["MaxLinkCountPhys"].asInteger(); } - if ( body.has("MaxPhysPrimScale") ) + if ( body.has("MaxPos") ) { - //IMPLEMENT ME + gHippoLimits->mMaxPrimXPos = body["MaxPosX"].asReal(); + gHippoLimits->mMaxPrimYPos = body["MaxPosY"].asReal(); + gHippoLimits->mMaxPrimZPos = body["MaxPosZ"].asReal(); + limitschanged = TRUE; } - if ( body.has("MaxPos") ) + if ( body.has("MinPos") ) { - //IMPLEMENT ME + gHippoLimits->mMinPrimXPos = body["MinPosX"].asReal(); + gHippoLimits->mMinPrimYPos = body["MinPosY"].asReal(); + gHippoLimits->mMinPrimZPos = body["MinPosZ"].asReal(); + limitschanged = TRUE; } if ( body.has("MaxPrimScale") ) { gHippoLimits->mMaxPrimScale = body["MaxPrimScale"].asReal(); limitschanged = TRUE; } - if ( body.has("MinPos") ) + if ( body.has("MaxPhysPrimScale") ) { //IMPLEMENT ME } @@ -128,32 +149,68 @@ class OpenRegionInfoUpdate : public LLHTTPNode } if ( body.has("OffsetOfUTC") ) { - //IMPLEMENT ME + gSavedSettings.setS32("TimeOffset", body["OffsetOfUTC"].asReal()); + gSavedSettings.setBOOL("UseTimeOffset", true); + } + if ( body.has("OffsetOfUTCDST") ) + { + gSavedSettings.setBOOL("TimeOffsetDST", body["OffsetOfUTCDST"].asInteger() == 1 ? TRUE : FALSE); } if ( body.has("RenderWater") ) { - gSavedSettings.setBOOL("RenderWater", body["RenderWater"].asBoolean()); + gHippoLimits->mRenderWater = body["RenderWater"].asInteger() == 1 ? TRUE : FALSE; + gAgent.getRegion()->rebuildWater(); } if ( body.has("SayDistance") ) { - //IMPLEMENT ME + gSavedSettings.setU32("ChatDistance", body["SayDistance"].asReal()); } if ( body.has("ShoutDistance") ) { //IMPLEMENT ME } + if ( body.has("WhisperDistance") ) + { + //IMPLEMENT ME + } if ( body.has("ToggleTeenMode") ) { - gSavedSettings.setBOOL("ToggleTeenMode", body["ToggleTeenMode"].asBoolean()); - + gHippoLimits->mEnableTeenMode = body["ToggleTeenMode"].asInteger() == 1 ? TRUE : FALSE; } - if ( body.has("WhisperDistance") ) + if ( body.has("SetTeenMode") ) { - //IMPLEMENT ME + gAgent.setTeen( body["SetTeenMode"].asInteger() == 1 ? TRUE : FALSE ); + LLFloaterWorldMap::reloadIcons(NULL); + llinfos << "PG status set to " << (S32)gAgent.isTeen() << llendl; + } + if ( body.has("ShowTags") ) + { + gHippoLimits->mRenderName = body["ShowTags"].asReal(); + } + if ( body.has("EnforceMaxBuild") ) + { + gHippoLimits->mEnforceMaxBuild = body["EnforceMaxBuild"].asInteger() == 1 ? TRUE : FALSE; + limitschanged = TRUE; + } + if ( body.has("MaxGroups") ) + { + gHippoLimits->mMaxAgentGroups = body["MaxGroups"].asReal(); + } + if ( body.has("AllowParcelWindLight") ) + { + gHippoLimits->mAllowParcelWindLight = body["AllowParcelWindLight"].asInteger() == 1; } if (limitschanged) gFloaterTools->updateToolsSizeLimits(); + + //Update the floater if its around + LLPanelRegionOpenSettingsInfo* floater = LLFloaterRegionInfo::getPanelOpenSettings(); + + if (floater != NULL) + { + floater->refreshFromRegion(gAgent.getRegion()); + } } }; diff --git a/linden/indra/newview/linux_tools/getvoice.sh b/linden/indra/newview/linux_tools/getvoice.sh deleted file mode 100755 index 13b632f36..000000000 --- a/linden/indra/newview/linux_tools/getvoice.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -SCRIPTSRC=`readlink -f "$0" || echo "$0"` -RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` - -#if mozilla-runtime-linux-x86_64 is present we are using 64bit Imprudence on 64bit Linux -if [ -d "${RUN_PATH}/app_settings/mozilla-runtime-linux-x86_64/" ]; then - LIB_INSTALLDIR="lib32/" # It's 32bit voice on 64bit Linux and 64bit viewer. Not using lib/ for avoiding ambiguity. -else - LIB_INSTALLDIR="lib/" # It's 32bit voice on 32 or 64bit Linux and 32bit viewer. -fi - -mkdir -p $LIB_INSTALLDIR -wget http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-linux-20090309.tar.bz2 -tar -C ./bin --strip-components 4 -xjf vivox-*.tar.bz2 --wildcards '*SLVoice' -tar -C ./$LIB_INSTALLDIR --strip-components 4 -xjf vivox-*.tar.bz2 --wildcards '*.so*' -rm vivox-*.tar.bz2 - -#now we have Vivox' OpenAL, but we want Imprudence (32bit for voice) OpenAL which is way better: -wget http://imprudenceviewer.org/download/libs/openal-linux32-20100426.tar.bz2 -tar -C ./$LIB_INSTALLDIR --strip-components 3 -xjf openal-*.tar.bz2 --wildcards '*openal.so*' -rm openal-*.tar.bz2 - -# For 64bit viewer on 64bit Linux we also need a 32bit libidn.so.11 and libuuid.so.1 -if [ -d ${RUN_PATH}/lib32/ ]; then - wget http://imprudenceviewer.org/download/libs/libidn20100312.tar.bz2 - tar -C $LIB_INSTALLDIR --strip-components 1 -xjf libidn*.tar.bz2 --wildcards '*.so*' - rm libidn*.tar.bz2 - - wget http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libuuid-linux-20090417.tar.bz2 - tar -C ./$LIB_INSTALLDIR --strip-components 3 -xjf libuuid-*.tar.bz2 --wildcards '*.so*' - rm libuuid-*.tar.bz2 -fi - diff --git a/linden/indra/newview/linux_tools/wrapper.sh b/linden/indra/newview/linux_tools/wrapper.sh index bc2c127a4..a43ebd5a4 100755 --- a/linden/indra/newview/linux_tools/wrapper.sh +++ b/linden/indra/newview/linux_tools/wrapper.sh @@ -107,16 +107,15 @@ if [ -n "$LL_TCMALLOC" ]; then fi fi -if([ "`uname -m`" = "x86_64" ] && [ -d "${RUN_PATH}/app_settings/mozilla-runtime-linux-x86_64/" ]); then - export GST_PLUGIN_PATH="${GST_PLUGIN_PATH}:${RUN_PATH}/lib64/gstreamer-plugins/" - - export SL_ENV='LD_LIBRARY_PATH="`pwd`"/lib64:"`pwd`"/lib32:"`pwd`"/app_settings/mozilla-runtime-linux-x86_64:"${LD_LIBRARY_PATH}"' +export VIEWER_BINARY='do-not-directly-run-imprudence-bin' +BINARY_TYPE=$(expr match "$(file -b bin/$VIEWER_BINARY)" '\(.*executable\)') +if [ "${BINARY_TYPE}" == "ELF 64-bit LSB executable" ]; then + export SL_ENV='LD_LIBRARY_PATH="`pwd`"/lib64:"`pwd`"/lib32:"${LD_LIBRARY_PATH}"' else - export GST_PLUGIN_PATH="${GST_PLUGIN_PATH}:${RUN_PATH}/lib/gstreamer-plugins/" - export SL_ENV='LD_LIBRARY_PATH="`pwd`"/lib:"`pwd`"/app_settings/mozilla-runtime-linux-i686:"${LD_LIBRARY_PATH}"' + export SL_ENV='LD_LIBRARY_PATH="`pwd`"/lib:"${LD_LIBRARY_PATH}"' fi -export SL_CMD='$LL_WRAPPER bin/do-not-directly-run-imprudence-bin' +export SL_CMD='$LL_WRAPPER bin/$VIEWER_BINARY' export SL_OPT="`cat gridargs.dat` $@" # Run the program diff --git a/linden/indra/newview/llagent.cpp b/linden/indra/newview/llagent.cpp index eb5cf9bce..5a1700af0 100644 --- a/linden/indra/newview/llagent.cpp +++ b/linden/indra/newview/llagent.cpp @@ -36,7 +36,6 @@ #include "stdenums.h" #include "llagent.h" - #include "llcamera.h" #include "llcoordframe.h" #include "indra_constants.h" @@ -77,6 +76,7 @@ #include "llfloaterdirectory.h" #include "llfloatergroupinfo.h" #include "llfloatergroups.h" +#include "llfloaterland.h" #include "llfloatermap.h" #include "llfloatermute.h" #include "llfloatersnapshot.h" @@ -109,10 +109,12 @@ #include "lltoolmgr.h" #include "lltoolpie.h" #include "lltoolview.h" +#include "lltrans.h" #include "llui.h" // for make_ui_sound #include "llurldispatcher.h" #include "llviewercamera.h" #include "llviewerinventory.h" +#include "llviewermediafocus.h" #include "llviewermenu.h" #include "llviewernetwork.h" #include "llviewerobjectlist.h" @@ -405,7 +407,17 @@ LLAgent::LLAgent() : mWearablesLoaded(FALSE), mTextureCacheQueryID(0), mAppearanceSerialNum(0), - mbTeleportKeepsLookAt(false) + mbTeleportKeepsLookAt(false), + + mLureShow(FALSE), + mLureName(""), + mLurePosGlobal(), + mLureGlobalX(0), + mLureGlobalY(0), + mLureX(0), + mLureY(0), + mLureZ(0), + mLureMaturityString("") { U32 i; for (i = 0; i < TOTAL_CONTROLS; i++) @@ -430,6 +442,7 @@ LLAgent::LLAgent() : void LLAgent::init() { mDrawDistance = gSavedSettings.getF32("RenderFarClip"); + mLockedDrawDistance = FALSE; // *Note: this is where LLViewerCamera::getInstance() used to be constructed. @@ -5560,7 +5573,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode !input.has("body") ) { //what to do with badly formed message? - response->status(400); + response->statusUnknownError(400); response->result(LLSD("Invalid message parameters")); } @@ -5633,7 +5646,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode else { //what to do with badly formed message? - response->status(400); + response->statusUnknownError(400); response->result(LLSD("Invalid message parameters")); } } @@ -6015,6 +6028,14 @@ void LLAgent::setHomePosRegion( const U64& region_handle, const LLVector3& pos_r mHomePosRegion = pos_region; } +void LLAgent::takeHomeScreenshot() +{ + std::string snap_filename = gDirUtilp->getLindenUserDir(); + snap_filename += gDirUtilp->getDirDelimiter(); + snap_filename += SCREEN_HOME_FILENAME; + gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight(), FALSE, FALSE); +} + BOOL LLAgent::getHomePosGlobal( LLVector3d* pos_global ) { if(!mHaveHomePosition) @@ -6079,7 +6100,11 @@ bool LLAgent::teleportCore(bool is_local) LLFloaterWorldMap::hide(NULL); LLFloaterDirectory::hide(NULL); + // hide land floater too - it'll be out of date + LLFloaterLand::hideInstance(); + LLViewerParcelMgr::getInstance()->deselectLand(); + LLViewerMediaFocus::getInstance()->setFocusFace(false, NULL, 0, NULL); // Close all pie menus, deselect land, etc. // Don't change the camera until we know teleport succeeded. JC @@ -8080,5 +8105,65 @@ LLVector3 LLAgent::getLastCoords() return mLastCoordinates; } +void LLAgent::showLureDestination(const std::string fromname, const S32 global_x, const S32 global_y, const S32 x, const S32 y, const S32 z, const std::string maturity) +{ + const LLVector3d posglobal = LLVector3d(F64(global_x), F64(global_y), F64(0)); + LLSimInfo* siminfo; + siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(posglobal); + std::string sim_name; + LLWorldMap::getInstance()->simNameFromPosGlobal( posglobal, sim_name ); + + if (siminfo) + { + llinfos << fromname << "'s teleport lure is to " << sim_name.c_str() << " (" << maturity << ")" << llendl; + LLStringUtil::format_map_t args; + args["[NAME]"] = fromname; + args["[DESTINATION]"] = LLURLDispatcher::buildSLURL(sim_name.c_str(), S32(x), S32(y), S32(z)); + std::string msg = LLTrans::getString("TeleportLureMaturity", args); + if (maturity != "") + { + msg.append(llformat(" (%s)", maturity.c_str())); + } + LLChat chat(msg); + LLFloaterChat::addChat(chat); + } + else + { + mLureShow = TRUE; + mLureName = fromname; + mLurePosGlobal = posglobal; + mLureGlobalX = U16(global_x / 256); + mLureGlobalY = U16(global_y / 256); + mLureX = x; + mLureY = y; + mLureZ = z; + mLureMaturityString = maturity; + LLWorldMap::getInstance()->sendMapBlockRequest(mLureGlobalX, mLureGlobalY, mLureGlobalX, mLureGlobalY, true); + } +} + +void LLAgent::onFoundLureDestination() +{ + mLureShow = FALSE; + LLSimInfo* siminfo; + siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(mLurePosGlobal); + std::string sim_name; + LLWorldMap::getInstance()->simNameFromPosGlobal( mLurePosGlobal, sim_name ); + + if (siminfo && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))) + { + llinfos << mLureName << " is offering a TP to " << sim_name.c_str() << " (" << mLureMaturityString << ")" << llendl; + LLStringUtil::format_map_t args; + args["[NAME]"] = mLureName; + args["[DESTINATION]"] = LLURLDispatcher::buildSLURL(sim_name.c_str(), S32(mLureX), S32(mLureY), S32(mLureZ)); + std::string msg = LLTrans::getString("TeleportOfferMaturity", args); + if (mLureMaturityString != "") + { + msg.append(llformat(" (%s)", mLureMaturityString.c_str())); + } + LLChat chat(msg); + LLFloaterChat::addChat(chat); + } +} // EOF diff --git a/linden/indra/newview/llagent.h b/linden/indra/newview/llagent.h index 141c72c3d..fe50bf5a7 100644 --- a/linden/indra/newview/llagent.h +++ b/linden/indra/newview/llagent.h @@ -584,6 +584,7 @@ class LLAgent : public LLObservable EPointAtType getPointAtType(); void setHomePosRegion( const U64& region_handle, const LLVector3& pos_region ); + void takeHomeScreenshot(); BOOL getHomePosGlobal( LLVector3d* pos_global ); void setCameraAnimating( BOOL b ) { mCameraAnimating = b; } BOOL getCameraAnimating( ) { return mCameraAnimating; } @@ -742,6 +743,7 @@ class LLAgent : public LLObservable LLUUID mSecureSessionID; // secure token for this login session F32 mDrawDistance; + BOOL mLockedDrawDistance; U64 mGroupPowers; BOOL mHideGroupTitle; @@ -782,6 +784,19 @@ class LLAgent : public LLObservable LLFrameTimer mDoubleTapRunTimer; EDoubleTapRunMode mDoubleTapRunMode; + BOOL mLureShow; + std::string mLureName; + LLVector3d mLurePosGlobal; + U16 mLureGlobalX; + U16 mLureGlobalY; + S32 mLureX; + S32 mLureY; + S32 mLureZ; + std::string mLureMaturityString; + + void showLureDestination(const std::string fromname, const S32 global_x, const S32 global_y, const S32 x, const S32 y, const S32 z, const std::string maturity); + void onFoundLureDestination(); + private: bool mbTeleportKeepsLookAt; bool mbAlwaysRun; // should the avatar run by default rather than walk diff --git a/linden/indra/newview/llappviewer.cpp b/linden/indra/newview/llappviewer.cpp index 4485cdfe3..19a0163d0 100644 --- a/linden/indra/newview/llappviewer.cpp +++ b/linden/indra/newview/llappviewer.cpp @@ -62,7 +62,8 @@ #include "llviewerdisplay.h" #include "llviewermedia.h" #include "llv4math.h" // for LL_VECTORIZE - +#include "llviewerparcelmedia.h" +#include "llviewermediafocus.h" #include "llviewermessage.h" #include "llviewerobjectlist.h" #include "llworldmap.h" @@ -103,7 +104,8 @@ #include "llassetstorage.h" #include "llpolymesh.h" #include "llcachename.h" -#include "audioengine.h" +#include "llaudioengine.h" +#include "llstreamingaudio.h" #include "llviewermenu.h" #include "llselectmgr.h" #include "lltrans.h" @@ -174,9 +176,9 @@ #include "llcommandlineparser.h" -#include "hippoGridManager.h" -#include "hippoLimits.h" -#include "hippoUpdate.h" +#include "hippogridmanager.h" +#include "hippolimits.h" +#include "hippoupdate.h" // [RLVa:KB] #include "rlvhandler.h" @@ -360,7 +362,7 @@ void request_initial_instant_messages() static BOOL requested = FALSE; if (!requested && gMessageSystem - && LLMuteList::getInstance()->isLoaded() + //&& LLMuteList::getInstance()->isLoaded() //We don't always want to have a mute list module && gAgent.getAvatarObject()) { // Auto-accepted inventory items may require the avatar object @@ -600,7 +602,10 @@ bool LLAppViewer::init() gDirUtilp->setSkinFolder("default"); initLogging(); - + + // Logging is initialized. Now it's safe to start the error thread. + startErrorThread(); + // // OK to write stuff to logs now, we've now crash reported if necessary // @@ -716,8 +721,15 @@ bool LLAppViewer::init() LLViewerJointMesh::updateVectorize(); // load MIME type -> media impl mappings - LLMIMETypes::parseMIMETypes( std::string("mime_types.xml") ); - + std::string mime_types_name; +#if LL_DARWIN + mime_types_name = "mime_types_mac.xml"; +#elif LL_LINUX + mime_types_name = "mime_types_linux.xml"; +#else + mime_types_name = "mime_types_windows.xml"; +#endif + LLMIMETypes::parseMIMETypes( mime_types_name ); // Copy settings to globals. *TODO: Remove or move to appropriage class initializers settings_to_globals(); @@ -911,7 +923,7 @@ bool LLAppViewer::mainLoop() //------------------------------------------- // Create IO Pump to use for HTTP Requests. - gServicePump = new LLPumpIO(gAPRPoolp); + gServicePump = new LLPumpIO; LLHTTPClient::setPump(*gServicePump); LLCurl::setCAFile(gDirUtilp->getCAFile()); @@ -1076,9 +1088,7 @@ bool LLAppViewer::mainLoop() } - const F64 min_frame_time = 0.0; //(.0333 - .0010); // max video frame rate = 30 fps - const F64 min_idle_time = 0.0; //(.0010); // min idle time = 1 ms - const F64 max_idle_time = run_multiple_threads ? min_idle_time : llmin(.005*10.0*gFrameTimeSeconds, 0.005); // 5 ms a second + const F64 max_idle_time = run_multiple_threads ? 0.0 : llmin(.005*10.0*gFrameIntervalSeconds, 0.005); // 50ms/second, no more than 5ms/frame idleTimer.reset(); while(1) { @@ -1094,11 +1104,8 @@ bool LLAppViewer::mainLoop() ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up } - F64 frame_time = frameTimer.getElapsedTimeF64(); F64 idle_time = idleTimer.getElapsedTimeF64(); - if (frame_time >= min_frame_time && - idle_time >= min_idle_time && - (!work_pending || idle_time >= max_idle_time)) + if (!work_pending || idle_time >= max_idle_time) { break; } @@ -1199,7 +1206,10 @@ bool LLAppViewer::cleanup() //reset balance for not playing the UI-Sound //when relogging into another account - gStatusBar->clearBalance(); + if (gStatusBar) + { + gStatusBar->clearBalance(); + } if (mQuitRequested) { @@ -1273,6 +1283,14 @@ bool LLAppViewer::cleanup() if (gAudiop) { + // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem. + + LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl(); + delete sai; + gAudiop->setStreamingAudioImpl(NULL); + + // shut down the audio subsystem + bool want_longname = false; if (gAudiop->getDriverName(want_longname) == "FMOD") { @@ -1502,7 +1520,9 @@ bool LLAppViewer::cleanup() //Note: //LLViewerMedia::cleanupClass() has to be put before gImageList.shutdown() //because some new image might be generated during cleaning up media. --bao + LLViewerMediaFocus::cleanupClass(); LLViewerMedia::cleanupClass(); + LLViewerParcelMedia::cleanupClass(); gImageList.shutdown(); // shutdown again in case a callback added something LLUIImageList::getInstance()->cleanUp(); @@ -1644,8 +1664,9 @@ bool LLAppViewer::initLogging() return true; } -bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, - bool set_defaults) +bool LLAppViewer::loadSettingsFromDirectory(AIReadAccess<settings_map_type> const& settings_r, + std::string const& location_key, + bool set_defaults) { // Find and vet the location key. if(!mSettingsLocationList.has(location_key)) @@ -1672,11 +1693,13 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, LLSD files = location.get("Files"); for(LLSD::map_iterator itr = files.beginMap(); itr != files.endMap(); ++itr) { - std::string settings_group = (*itr).first; + std::string const settings_group = (*itr).first; + settings_map_type::const_iterator const settings_group_iter = settings_r->find(settings_group); + llinfos << "Attempting to load settings for the group " << settings_group << " - from location " << location_key << llendl; - if(gSettings.find(settings_group) == gSettings.end()) + if(settings_group_iter == settings_r->end()) { llwarns << "No matching settings group for name " << settings_group << llendl; continue; @@ -1690,11 +1713,10 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, std::string custom_name_setting = file.get("NameFromSetting"); // *NOTE: Regardless of the group currently being lodaed, // this setting is always read from the Global settings. - if(gSettings[sGlobalSettingsName]->controlExists(custom_name_setting)) + LLControlGroup const* control_group = settings_r->find(sGlobalSettingsName)->second; + if(control_group->controlExists(custom_name_setting)) { - std::string file_name = - gSettings[sGlobalSettingsName]->getString(custom_name_setting); - full_settings_path = file_name; + full_settings_path = control_group->getString(custom_name_setting); } } @@ -1710,7 +1732,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, requirement = file.get("Requirement").asInteger(); } - if(!gSettings[settings_group]->loadFromFile(full_settings_path, set_defaults)) + if(!settings_group_iter->second->loadFromFile(full_settings_path, set_defaults)) { if(requirement == 1) { @@ -1755,10 +1777,14 @@ bool LLAppViewer::initConfiguration() // init Imprudence version - MC ViewerVersion::initViewerVersion(); + // Grab and hold write locks for the entire duration of this function. + AIWriteAccess<settings_map_type> settings_w(gSettings); + settings_map_type& settings(*settings_w); + //Set up internal pointers - gSettings[sGlobalSettingsName] = &gSavedSettings; - gSettings[sPerAccountSettingsName] = &gSavedPerAccountSettings; - gSettings[sCrashSettingsName] = &gCrashSettings; + settings[sGlobalSettingsName] = &gSavedSettings; + settings[sPerAccountSettingsName] = &gSavedPerAccountSettings; + settings[sCrashSettingsName] = &gCrashSettings; //Load settings files list std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml"); @@ -1783,7 +1809,7 @@ bool LLAppViewer::initConfiguration() // - load defaults bool set_defaults = true; - if(!loadSettingsFromDirectory("Default", set_defaults)) + if(!loadSettingsFromDirectory(settings_w, "Default", set_defaults)) { std::ostringstream msg; msg << "Second Life could not load its default settings file. \n" @@ -1893,7 +1919,7 @@ bool LLAppViewer::initConfiguration() } // - load overrides from user_settings - loadSettingsFromDirectory("User"); + loadSettingsFromDirectory(settings_w, "User"); // - apply command line settings clp.notify(); @@ -1963,7 +1989,7 @@ bool LLAppViewer::initConfiguration() { const std::string& name = *itr; const std::string& value = *(++itr); - LLControlVariable* c = gSettings[sGlobalSettingsName]->getControl(name); + LLControlVariable* c = settings[sGlobalSettingsName]->getControl(name); if(c) { c->setValue(value, false); @@ -3265,12 +3291,15 @@ void LLAppViewer::saveFinalSnapshot() gSavedSettings.setBOOL("ShowParcelOwners", FALSE); idle(); - std::string snap_filename = gDirUtilp->getLindenUserDir(); - snap_filename += gDirUtilp->getDirDelimiter(); - snap_filename += SCREEN_LAST_FILENAME; - // use full pixel dimensions of viewer window (not post-scale dimensions) - gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight(), FALSE, TRUE); - mSavedFinalSnapshot = TRUE; + std::string snap_filename = gDirUtilp->getLindenUserDir(true); + if (!snap_filename.empty()) + { + snap_filename += gDirUtilp->getDirDelimiter(); + snap_filename += SCREEN_LAST_FILENAME; + // use full pixel dimensions of viewer window (not post-scale dimensions) + gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight(), FALSE, TRUE); + mSavedFinalSnapshot = TRUE; + } } } @@ -3689,6 +3718,9 @@ void LLAppViewer::idle() gAgent.updateCamera(); } + // update media focus + LLViewerMediaFocus::getInstance()->update(); + // objects and camera should be in sync, do LOD calculations now { LLFastTimer t(LLFastTimer::FTM_LOD_UPDATE); diff --git a/linden/indra/newview/llappviewer.h b/linden/indra/newview/llappviewer.h index 9d72457d9..15fd9d6e2 100644 --- a/linden/indra/newview/llappviewer.h +++ b/linden/indra/newview/llappviewer.h @@ -33,6 +33,9 @@ #ifndef LL_LLAPPVIEWER_H #define LL_LLAPPVIEWER_H +#include "llsys.h" // LLOSInfo +#include "llviewercontrol.h" // settings_map_type + class LLTextureCache; class LLImageDecodeThread; class LLTextureFetch; @@ -133,11 +136,12 @@ class LLAppViewer : public LLApp // Load settings from the location specified by loction_key. // Key availale and rules for loading, are specified in // 'app_settings/settings_files.xml' - bool loadSettingsFromDirectory(const std::string& location_key, - bool set_defaults = false); + bool loadSettingsFromDirectory(AIReadAccess<settings_map_type> const& settings_r, + std::string const& location_key, + bool set_defaults = false); - std::string getSettingsFilename(const std::string& location_key, - const std::string& file); + std::string getSettingsFilename(std::string const& location_key, + std::string const& file); // For thread debugging. // llstartup needs to control init. diff --git a/linden/indra/newview/llappviewerlinux.cpp b/linden/indra/newview/llappviewerlinux.cpp index bfad899e4..88ddf7ef7 100644 --- a/linden/indra/newview/llappviewerlinux.cpp +++ b/linden/indra/newview/llappviewerlinux.cpp @@ -129,6 +129,7 @@ int main( int argc, char **argv ) } delete viewer_app_ptr; viewer_app_ptr = NULL; + return 0; } @@ -437,7 +438,7 @@ gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **succ llinfos << "Was asked to go to slurl: " << slurl << llendl; std::string url = slurl; - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; if (LLURLDispatcher::dispatch(url, web, trusted_browser)) { diff --git a/linden/indra/newview/llappviewermacosx.cpp b/linden/indra/newview/llappviewermacosx.cpp index 1f5b7dcfd..d81b6e3c5 100644 --- a/linden/indra/newview/llappviewermacosx.cpp +++ b/linden/indra/newview/llappviewermacosx.cpp @@ -1,6 +1,6 @@ /** * @file llappviewermacosx.cpp - * @brief The LLAppViewerWin32 class definitions + * @brief The LLAppViewerMacOSX class definitions * * $LicenseInfo:firstyear=2007&license=viewergpl$ * @@ -119,6 +119,7 @@ int main( int argc, char **argv ) } delete viewer_app_ptr; viewer_app_ptr = NULL; + return 0; } @@ -474,7 +475,7 @@ OSErr AEGURLHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn) url.replace(0, prefix.length(), "secondlife:///app/"); } - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; LLURLDispatcher::dispatch(url, web, trusted_browser); } diff --git a/linden/indra/newview/llassetuploadresponders.cpp b/linden/indra/newview/llassetuploadresponders.cpp index aff1fb8cd..d4a75f72c 100644 --- a/linden/indra/newview/llassetuploadresponders.cpp +++ b/linden/indra/newview/llassetuploadresponders.cpp @@ -63,7 +63,7 @@ #include "llscrolllistctrl.h" #include "llsdserialize.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // When uploading multiple files, don't display any of them when uploading more than this number. static const S32 FILE_COUNT_DISPLAY_THRESHOLD = 5; @@ -287,7 +287,8 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) LLInventoryView* view = LLInventoryView::getActiveInventory(); if(view) { - LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); + view->getPanel()->setSelection(content["new_inventory_item"].asUUID(), TAKE_FOCUS_NO); if((LLAssetType::AT_TEXTURE == asset_type || LLAssetType::AT_SOUND == asset_type) && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD) @@ -296,7 +297,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) } //LLInventoryView::dumpSelectionInformation((void*)view); // restore keyboard focus - gFocusMgr.setKeyboardFocus(focus_ctrl); + gFocusMgr.setKeyboardFocus(focus); } } else diff --git a/linden/indra/newview/llassetuploadresponders.h b/linden/indra/newview/llassetuploadresponders.h index c08f2999f..9102f6bc1 100644 --- a/linden/indra/newview/llassetuploadresponders.h +++ b/linden/indra/newview/llassetuploadresponders.h @@ -74,6 +74,7 @@ class LLNewAgentInventoryResponder : public LLAssetUploadResponder class LLBakedUploadData; class LLSendTexLayerResponder : public LLAssetUploadResponder { + LOG_CLASS(LLSendTexLayerResponder); public: LLSendTexLayerResponder(const LLSD& post_data, const LLUUID& vfile_id, diff --git a/linden/indra/newview/llaudiosourcevo.h b/linden/indra/newview/llaudiosourcevo.h index e7bb2837a..4b70f8bc2 100644 --- a/linden/indra/newview/llaudiosourcevo.h +++ b/linden/indra/newview/llaudiosourcevo.h @@ -34,7 +34,7 @@ #ifndef LL_LLAUDIOSOURCEVO_H #define LL_LLAUDIOSOURCEVO_H -#include "audioengine.h" +#include "llaudioengine.h" #include "llviewerobject.h" class LLViewerObject; diff --git a/linden/indra/newview/llchatbar.cpp b/linden/indra/newview/llchatbar.cpp index 0633c8da8..2f2ad1660 100644 --- a/linden/indra/newview/llchatbar.cpp +++ b/linden/indra/newview/llchatbar.cpp @@ -946,7 +946,7 @@ class LLChatHandler : public LLCommandHandler // Your code here bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { if (tokens.size() < 2) return false; S32 channel = tokens[0].asInteger(); diff --git a/linden/indra/newview/llcloud.cpp b/linden/indra/newview/llcloud.cpp index 0099817de..3e9b86a3b 100644 --- a/linden/indra/newview/llcloud.cpp +++ b/linden/indra/newview/llcloud.cpp @@ -38,6 +38,7 @@ #include "v4math.h" #include "llquaternion.h" #include "v4color.h" +#include "llviewercontrol.h" #include "llwind.h" #include "llcloud.h" @@ -56,15 +57,6 @@ extern LLPipeline gPipeline; -const F32 CLOUD_UPDATE_RATE = 1.0f; // Global time dilation for clouds -const F32 CLOUD_GROW_RATE = 0.05f; -const F32 CLOUD_DECAY_RATE = -0.05f; -const F32 CLOUD_VELOCITY_SCALE = 0.01f; -const F32 CLOUD_DENSITY = 25.f; -const S32 CLOUD_COUNT_MAX = 20; -const F32 CLOUD_HEIGHT_RANGE = 48.f; -const F32 CLOUD_HEIGHT_MEAN = 192.f; - enum { LL_PUFF_GROWING = 0, @@ -80,7 +72,7 @@ S32 LLCloudPuff::sPuffCount = 0; LLCloudPuff::LLCloudPuff() : mAlpha(0.01f), - mRate(CLOUD_GROW_RATE*CLOUD_UPDATE_RATE), + mRate((gSavedSettings.getF32("CloudGrowRate")/100)*gSavedSettings.getF32("CloudUpdateRate")), mLifeState(LL_PUFF_GROWING) { } @@ -121,7 +113,7 @@ void LLCloudGroup::updatePuffs(const F32 dt) mVOCloudsp->setPositionRegion(mCenterRegion); mVOCloudsp->setScale(LLVector3(256.f/CLOUD_GROUPS_PER_EDGE + CLOUD_PUFF_WIDTH, 256.f/CLOUD_GROUPS_PER_EDGE + CLOUD_PUFF_WIDTH, - CLOUD_HEIGHT_RANGE + CLOUD_PUFF_HEIGHT)*0.5f); + gSavedSettings.getF32("ClassicCloudRange") + CLOUD_PUFF_HEIGHT)*0.5f); gPipeline.createObject(mVOCloudsp); } @@ -132,7 +124,7 @@ void LLCloudGroup::updatePuffs(const F32 dt) { LLCloudPuff &puff = mCloudPuffs[i]; velocity = mCloudLayerp->getRegion()->mWind.getCloudVelocity(mCloudLayerp->getRegion()->getPosRegionFromGlobal(puff.mPositionGlobal)); - velocity *= CLOUD_VELOCITY_SCALE*CLOUD_UPDATE_RATE; + velocity *= (gSavedSettings.getF32("CloudVelocityScale")/100)*gSavedSettings.getF32("CloudUpdateRate"); vel_d.setVec(velocity); mCloudPuffs[i].mPositionGlobal += vel_d; mCloudPuffs[i].mAlpha += mCloudPuffs[i].mRate * dt; @@ -163,7 +155,7 @@ void LLCloudGroup::updatePuffOwnership() { //llinfos << "Killing puff not in group" << llendl; mCloudPuffs[i].setLifeState(LL_PUFF_DYING); - mCloudPuffs[i].mRate = CLOUD_DECAY_RATE*CLOUD_UPDATE_RATE; + mCloudPuffs[i].mRate = (gSavedSettings.getF32("CloudDecayRate")/100)*gSavedSettings.getF32("CloudUpdateRate"); i++; continue; } @@ -185,9 +177,9 @@ void LLCloudGroup::updatePuffCount() return; } S32 i; - S32 target_puff_count = llround(CLOUD_DENSITY * mDensity); + S32 target_puff_count = llround((S32)gSavedSettings.getF32("CloudDensity") * mDensity); target_puff_count = llmax(0, target_puff_count); - target_puff_count = llmin(CLOUD_COUNT_MAX, target_puff_count); + target_puff_count = llmin((S32)gSavedSettings.getF32("CloudCountMax"), target_puff_count); S32 current_puff_count = (S32) mCloudPuffs.size(); // Create a new cloud if we need one if (current_puff_count < target_puff_count) @@ -199,7 +191,7 @@ void LLCloudGroup::updatePuffCount() puff_pos_global = mVOCloudsp->getPositionGlobal(); F32 x = ll_frand(256.f/CLOUD_GROUPS_PER_EDGE) - 128.f/CLOUD_GROUPS_PER_EDGE; F32 y = ll_frand(256.f/CLOUD_GROUPS_PER_EDGE) - 128.f/CLOUD_GROUPS_PER_EDGE; - F32 z = ll_frand(CLOUD_HEIGHT_RANGE) - 0.5f*CLOUD_HEIGHT_RANGE; + F32 z = ll_frand(gSavedSettings.getF32("ClassicCloudRange")) - 0.5f*gSavedSettings.getF32("ClassicCloudRange"); puff_pos_global += LLVector3d(x, y, z); mCloudPuffs[i].mPositionGlobal = puff_pos_global; mCloudPuffs[i].mAlpha = 0.01f; @@ -227,7 +219,7 @@ void LLCloudGroup::updatePuffCount() { //llinfos << "Killing extra live cloud" << llendl; mCloudPuffs[i].setLifeState(LL_PUFF_DYING); - mCloudPuffs[i].mRate = CLOUD_DECAY_RATE*CLOUD_UPDATE_RATE; + mCloudPuffs[i].mRate = (gSavedSettings.getF32("CloudDecayRate")/100)*gSavedSettings.getF32("CloudUpdateRate"); new_dying_count--; } i++; @@ -294,7 +286,7 @@ LLCloudLayer::LLCloudLayer() x = (0.5f + j)*(256.f/CLOUD_GROUPS_PER_EDGE); mCloudGroups[i][j].setCloudLayerp(this); - mCloudGroups[i][j].setCenterRegion(LLVector3(x, y, CLOUD_HEIGHT_MEAN)); + mCloudGroups[i][j].setCenterRegion(LLVector3(x, y, gSavedSettings.getF32("ClassicCloudHeight"))); } } } @@ -344,12 +336,10 @@ void LLCloudLayer::destroy() mWindp = NULL; } - void LLCloudLayer::reset() { } - void LLCloudLayer::setWindPointer(LLWind *windp) { if (mWindp) diff --git a/linden/indra/newview/llcommandhandler.cpp b/linden/indra/newview/llcommandhandler.cpp index 422c94ade..a04182a91 100644 --- a/linden/indra/newview/llcommandhandler.cpp +++ b/linden/indra/newview/llcommandhandler.cpp @@ -55,7 +55,7 @@ class LLCommandHandlerRegistry bool dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); private: @@ -84,7 +84,7 @@ void LLCommandHandlerRegistry::add(const char* cmd, bool require_trusted_browser bool LLCommandHandlerRegistry::dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { std::map<std::string, LLCommandHandlerInfo>::iterator it = mMap.find(cmd); @@ -126,7 +126,7 @@ LLCommandHandler::~LLCommandHandler() bool LLCommandDispatcher::dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { return LLCommandHandlerRegistry::instance().dispatch( diff --git a/linden/indra/newview/llcommandhandler.h b/linden/indra/newview/llcommandhandler.h index ab4c2cc48..5cb3ee73d 100644 --- a/linden/indra/newview/llcommandhandler.h +++ b/linden/indra/newview/llcommandhandler.h @@ -47,7 +47,7 @@ class LLFooHandler : public LLCommandHandler // Your code here bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { if (tokens.size() < 1) return false; LLUUID id( tokens[0] ); @@ -60,7 +60,7 @@ LLFooHandler gFooHandler; */ -class LLWebBrowserCtrl; +class LLMediaCtrl; class LLCommandHandler { @@ -68,14 +68,14 @@ class LLCommandHandler LLCommandHandler(const char* command, bool allow_from_untrusted_browser); // Automatically registers object to get called when // command is executed. All commands can be processed - // in links from LLWebBrowserCtrl, but some (like teleport) + // in links from LLMediaCtrl, but some (like teleport) // should not be allowed from outside the app. virtual ~LLCommandHandler(); virtual bool handle(const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web) = 0; + LLMediaCtrl* web) = 0; // For URL secondlife:///app/foo/bar/baz?cat=1&dog=2 // @params - array of "bar", "baz", possibly empty // @query_map - map of "cat" -> 1, "dog" -> 2, possibly empty @@ -91,7 +91,7 @@ class LLCommandDispatcher static bool dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); // Execute a command registered via the above mechanism, // passing string parameters. diff --git a/linden/indra/newview/llcurrencyuimanager.cpp b/linden/indra/newview/llcurrencyuimanager.cpp index 99d043053..07b1287e8 100644 --- a/linden/indra/newview/llcurrencyuimanager.cpp +++ b/linden/indra/newview/llcurrencyuimanager.cpp @@ -47,7 +47,7 @@ #include "llxmlrpctransaction.h" #include "llviewernetwork.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" const F64 CURRENCY_ESTIMATE_FREQUENCY = 2.0; // how long of a pause in typing a currency buy amount before an diff --git a/linden/indra/newview/llfeaturemanager.cpp b/linden/indra/newview/llfeaturemanager.cpp index 54da31b93..bf43fcfeb 100644 --- a/linden/indra/newview/llfeaturemanager.cpp +++ b/linden/indra/newview/llfeaturemanager.cpp @@ -62,7 +62,6 @@ // externs // extern LLMemoryInfo gSysMemory; -extern LLCPUInfo gSysCPU; #if LL_DARWIN const char FEATURE_TABLE_FILENAME[] = "featuretable_mac.txt"; diff --git a/linden/indra/newview/llfilepicker.cpp b/linden/indra/newview/llfilepicker.cpp index a59fa0683..ec4e294a5 100644 --- a/linden/indra/newview/llfilepicker.cpp +++ b/linden/indra/newview/llfilepicker.cpp @@ -1181,7 +1181,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename break; case FFSAVE_RAW: caption += add_simple_pattern_filter_to_gtkchooser - (picker, "*.raw", LLTrans::getString("dot_raw_file") + " (*.raw)"); + (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); suggest_ext = ".raw"; break; case FFSAVE_J2C: diff --git a/linden/indra/newview/llfirstuse.cpp b/linden/indra/newview/llfirstuse.cpp index 0b777ea45..18efa9ea8 100644 --- a/linden/indra/newview/llfirstuse.cpp +++ b/linden/indra/newview/llfirstuse.cpp @@ -47,7 +47,7 @@ #include "floatergriddefault.h" #include "floatervoicelicense.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include "llstartup.h" #include "llvoavatar.h" diff --git a/linden/indra/newview/llfloaterabout.cpp b/linden/indra/newview/llfloaterabout.cpp index 9c1d67b48..f7163ee2e 100644 --- a/linden/indra/newview/llfloaterabout.cpp +++ b/linden/indra/newview/llfloaterabout.cpp @@ -42,9 +42,9 @@ #include "llcurl.h" #include "llimagej2c.h" -#include "audioengine.h" +#include "llaudioengine.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include "llviewertexteditor.h" #include "llviewercontrol.h" #include "llagent.h" @@ -57,7 +57,6 @@ #include "lltrans.h" #include "llappviewer.h" #include "llglheaders.h" -#include "llmediamanager.h" #include "llwindow.h" #include "viewerversion.h" @@ -69,7 +68,6 @@ #include "lldxhardware.h" #endif -extern LLCPUInfo gSysCPU; extern LLMemoryInfo gSysMemory; extern U32 gPacketsIn; @@ -246,26 +244,10 @@ LLFloaterAbout::LLFloaterAbout() support.append("\n"); - LLMediaManager *mgr = LLMediaManager::getInstance(); - if (mgr) - { - LLMediaBase *gstreamer = mgr->createSourceFromMimeType("http", "audio/mpeg"); - if (gstreamer) - { - support.append("GStreamer Version: "); - support.append( gstreamer->getVersion() ); - support.append("\n"); - } - - LLMediaBase *media_source = mgr->createSourceFromMimeType("http", "text/html"); - if (media_source) - { - support.append("LLMozLib Version: "); - support.append(media_source->getVersion()); - support.append("\n"); - mgr->destroySource(media_source); - } - } + // TODO: Implement media plugin version query + + support.append("Qt Webkit Version: 4.6 (version number hard-coded)"); + support.append("\n"); if (gPacketsIn > 0) { diff --git a/linden/indra/newview/llfloateranimpreview.cpp b/linden/indra/newview/llfloateranimpreview.cpp index 09d3b2cbf..232530c2b 100644 --- a/linden/indra/newview/llfloateranimpreview.cpp +++ b/linden/indra/newview/llfloateranimpreview.cpp @@ -68,7 +68,7 @@ #include "pipeline.h" #include "lluictrlfactory.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" S32 LLFloaterAnimPreview::sUploadAmount = 10; diff --git a/linden/indra/newview/llfloateravatarinfo.cpp b/linden/indra/newview/llfloateravatarinfo.cpp index 21f160e04..06188750c 100644 --- a/linden/indra/newview/llfloateravatarinfo.cpp +++ b/linden/indra/newview/llfloateravatarinfo.cpp @@ -63,7 +63,7 @@ class LLAgentHandler : public LLCommandHandler LLAgentHandler() : LLCommandHandler("agent", true) { } bool handle(const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { if (params.size() < 2) return false; LLUUID agent_id; diff --git a/linden/indra/newview/llfloaterbuy.cpp b/linden/indra/newview/llfloaterbuy.cpp index 86cab43f6..99c9fed5d 100644 --- a/linden/indra/newview/llfloaterbuy.cpp +++ b/linden/indra/newview/llfloaterbuy.cpp @@ -50,7 +50,7 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" LLFloaterBuy* LLFloaterBuy::sInstance = NULL; diff --git a/linden/indra/newview/llfloaterbuycontents.cpp b/linden/indra/newview/llfloaterbuycontents.cpp index 498d6acc4..e16f98dff 100644 --- a/linden/indra/newview/llfloaterbuycontents.cpp +++ b/linden/indra/newview/llfloaterbuycontents.cpp @@ -54,7 +54,7 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" LLFloaterBuyContents* LLFloaterBuyContents::sInstance = NULL; diff --git a/linden/indra/newview/llfloaterbuycurrency.cpp b/linden/indra/newview/llfloaterbuycurrency.cpp index 509649593..6a0dd6886 100644 --- a/linden/indra/newview/llfloaterbuycurrency.cpp +++ b/linden/indra/newview/llfloaterbuycurrency.cpp @@ -46,7 +46,7 @@ #include "llwindow.h" #include "llappviewer.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" static const S32 STANDARD_BUY_AMOUNT = 2000; static const S32 MINIMUM_BALANCE_AMOUNT = 0; diff --git a/linden/indra/newview/llfloaterbuyland.cpp b/linden/indra/newview/llfloaterbuyland.cpp index 75630b210..8288c581c 100644 --- a/linden/indra/newview/llfloaterbuyland.cpp +++ b/linden/indra/newview/llfloaterbuyland.cpp @@ -66,7 +66,7 @@ #include "llviewernetwork.h" #include "roles_constants.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // NOTE: This is duplicated in lldatamoney.cpp ... const F32 GROUP_LAND_BONUS_FACTOR = 1.1f; diff --git a/linden/indra/newview/llfloaterchat.cpp b/linden/indra/newview/llfloaterchat.cpp index 3f0b184f2..e9ea14b02 100644 --- a/linden/indra/newview/llfloaterchat.cpp +++ b/linden/indra/newview/llfloaterchat.cpp @@ -194,6 +194,15 @@ void LLFloaterChat::setMinimized(BOOL minimized) updateConsoleVisibility(); } +// linden library includes +#include "llaudioengine.h" +#include "llchat.h" +#include "llfontgl.h" +#include "llrect.h" +#include "llerror.h" +#include "llstring.h" +#include "llwindow.h" +#include "message.h" void LLFloaterChat::updateConsoleVisibility() { @@ -473,7 +482,7 @@ BOOL LLFloaterChat::isOwnNameInText(const std::string &text_line) for (int i=1; i<=3; i++) { std::stringstream key; - key << "nick0" << i; + key << "HighlightNickname0" << i; std::string nick = gSavedSettings.getString(key.str()); if (! nick.empty()) { @@ -587,13 +596,54 @@ void LLFloaterChat::addChat(const LLChat& chat, if(from_instant_message && gSavedSettings.getBOOL("IMInChatHistory")) addChatHistory(chat,false); - LLTextParser* highlight = LLTextParser::getInstance(); - highlight->triggerAlerts(gAgent.getID(), gAgent.getPositionGlobal(), chat.mText, gViewerWindow->getWindow()); + triggerAlerts(chat.mText); if(!from_instant_message) addChatHistory(chat); } +// Moved from lltextparser.cpp to break llui/llaudio library dependency. +//static +void LLFloaterChat::triggerAlerts(const std::string& text) +{ + LLTextParser* parser = LLTextParser::getInstance(); +// bool spoken=FALSE; + for (S32 i=0;i<parser->mHighlights.size();i++) + { + LLSD& highlight = parser->mHighlights[i]; + if (parser->findPattern(text,highlight) >= 0 ) + { + if(gAudiop) + { + if ((std::string)highlight["sound_lluuid"] != LLUUID::null.asString()) + { + gAudiop->triggerSound(highlight["sound_lluuid"].asUUID(), + gAgent.getID(), + 1.f, + LLAudioEngine::AUDIO_TYPE_UI, + gAgent.getPositionGlobal() ); + } +/* + if (!spoken) + { + LLTextToSpeech* text_to_speech = NULL; + text_to_speech = LLTextToSpeech::getInstance(); + spoken = text_to_speech->speak((LLString)highlight["voice"],text); + } + */ + } + if (highlight["flash"]) + { + LLWindow* viewer_window = gViewerWindow->getWindow(); + if (viewer_window && viewer_window->getMinimized()) + { + viewer_window->flashIcon(5.f); + } + } + } + } +} + LLColor4 get_text_color(const LLChat& chat) { LLColor4 text_color; diff --git a/linden/indra/newview/llfloaterchat.h b/linden/indra/newview/llfloaterchat.h index 5a265672c..f8683b934 100644 --- a/linden/indra/newview/llfloaterchat.h +++ b/linden/indra/newview/llfloaterchat.h @@ -78,6 +78,8 @@ class LLFloaterChat // Add chat to history alone. static void addChatHistory(const LLChat& chat, bool log_to_file = true); + static void triggerAlerts(const std::string& text); + static void onClickMute(void *data); static void onClickToggleShowMute(LLUICtrl* caller, void *data); static void onClickToggleTranslateChat(LLUICtrl* caller, void *data); diff --git a/linden/indra/newview/llfloaterclassified.cpp b/linden/indra/newview/llfloaterclassified.cpp index d426e0421..07603039b 100644 --- a/linden/indra/newview/llfloaterclassified.cpp +++ b/linden/indra/newview/llfloaterclassified.cpp @@ -57,7 +57,7 @@ class LLClassifiedHandler : public LLCommandHandler // requires trusted browser to trigger LLClassifiedHandler() : LLCommandHandler("classified", true) { } bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { if (tokens.size() < 2) { diff --git a/linden/indra/newview/llfloaterdirectory.cpp b/linden/indra/newview/llfloaterdirectory.cpp index 8018c31f0..7c8ddf1d1 100644 --- a/linden/indra/newview/llfloaterdirectory.cpp +++ b/linden/indra/newview/llfloaterdirectory.cpp @@ -466,7 +466,9 @@ void LLFloaterDirectory::setVisible(BOOL visible) void LLFloaterDirectory::onClose(bool app_quitting) { - setVisible(FALSE); + LLFloater::onClose(app_quitting); + + //setVisible(FALSE); //meaning you hide 3 web browsers - one SLPlugin each } // static diff --git a/linden/indra/newview/llfloaterenvsettings.cpp b/linden/indra/newview/llfloaterenvsettings.cpp index 557a5e1d6..801ff49d3 100644 --- a/linden/indra/newview/llfloaterenvsettings.cpp +++ b/linden/indra/newview/llfloaterenvsettings.cpp @@ -47,6 +47,7 @@ #include "llwaterparammanager.h" #include "llmath.h" #include "llviewerwindow.h" +#include "wlfloatermanager.h" #include "pipeline.h" @@ -87,7 +88,7 @@ void LLFloaterEnvSettings::initCallbacks(void) // WL Top childSetAction("EnvAdvancedSkyButton", onOpenAdvancedSky, NULL); childSetAction("EnvAdvancedWaterButton", onOpenAdvancedWater, NULL); - childSetAction("EnvSubmitWindlight", onSubmitWindlight, NULL); + childSetAction("EnvWLManager", onOpenWLManager, NULL); childSetAction("EnvUseEstateTimeButton", onUseEstateTime, NULL); childSetAction("EnvSettingsHelpButton", onClickHelp, this); } @@ -285,6 +286,11 @@ void LLFloaterEnvSettings::onOpenAdvancedWater(void* userData) LLFloaterWater::show(); } +void LLFloaterEnvSettings::onOpenWLManager(void* userData) +{ + WLFloaterManager::show(); +} + void LLFloaterEnvSettings::onSubmitWindlight(void* userData) { Meta7WindlightPacket * wl = new Meta7WindlightPacket(); diff --git a/linden/indra/newview/llfloaterenvsettings.h b/linden/indra/newview/llfloaterenvsettings.h index 49bf4fd0d..8b4462105 100644 --- a/linden/indra/newview/llfloaterenvsettings.h +++ b/linden/indra/newview/llfloaterenvsettings.h @@ -78,6 +78,9 @@ class LLFloaterEnvSettings : public LLFloater /// open the advanced water settings menu static void onOpenAdvancedWater(void* userData); + /// open the windlight manager floater + static void onOpenWLManager(void* userData); + /// submit windlight settings to the estate static void onSubmitWindlight(void* userData); diff --git a/linden/indra/newview/llfloaterevent.cpp b/linden/indra/newview/llfloaterevent.cpp index 485c13c7b..0ec2a7637 100644 --- a/linden/indra/newview/llfloaterevent.cpp +++ b/linden/indra/newview/llfloaterevent.cpp @@ -58,7 +58,7 @@ class LLEventHandler : public LLCommandHandler // requires trusted browser to trigger LLEventHandler() : LLCommandHandler("event", true) { } bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { if (tokens.size() < 2) { diff --git a/linden/indra/newview/llfloatergodtools.cpp b/linden/indra/newview/llfloatergodtools.cpp index 461dfe258..f918e8a46 100644 --- a/linden/indra/newview/llfloatergodtools.cpp +++ b/linden/indra/newview/llfloatergodtools.cpp @@ -77,7 +77,7 @@ #include "lltransfertargetfile.h" #include "lltransfersourcefile.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" const F32 SECONDS_BETWEEN_UPDATE_REQUESTS = 5.0f; diff --git a/linden/indra/newview/llfloatergroupinfo.cpp b/linden/indra/newview/llfloatergroupinfo.cpp index 6fbd5e176..3ae7d5a87 100644 --- a/linden/indra/newview/llfloatergroupinfo.cpp +++ b/linden/indra/newview/llfloatergroupinfo.cpp @@ -60,7 +60,7 @@ class LLGroupHandler : public LLCommandHandler // requires trusted browser to trigger LLGroupHandler() : LLCommandHandler("group", true) { } bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { if (tokens.size() < 1) { diff --git a/linden/indra/newview/llfloatergroups.cpp b/linden/indra/newview/llfloatergroups.cpp index 79e9e3136..f7359236c 100644 --- a/linden/indra/newview/llfloatergroups.cpp +++ b/linden/indra/newview/llfloatergroups.cpp @@ -59,7 +59,7 @@ #include "llviewerwindow.h" #include "llimview.h" -#include "hippoLimits.h" +#include "hippolimits.h" // static std::map<const LLUUID, LLFloaterGroupPicker*> LLFloaterGroupPicker::sInstances; diff --git a/linden/indra/newview/llfloaterhandler.cpp b/linden/indra/newview/llfloaterhandler.cpp index f4c7e43a7..7cf715662 100644 --- a/linden/indra/newview/llfloaterhandler.cpp +++ b/linden/indra/newview/llfloaterhandler.cpp @@ -31,7 +31,7 @@ #include "llfloaterhandler.h" #include "llfloater.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" // register with dispatch via global object LLFloaterHandler gFloaterHandler; @@ -54,7 +54,7 @@ LLFloater* get_parent_floater(LLView* view) } -bool LLFloaterHandler::handle(const LLSD ¶ms, const LLSD &query_map, LLWebBrowserCtrl *web) +bool LLFloaterHandler::handle(const LLSD ¶ms, const LLSD &query_map, LLMediaCtrl *web) { if (params.size() < 2) return false; LLFloater* floater = NULL; diff --git a/linden/indra/newview/llfloaterhandler.h b/linden/indra/newview/llfloaterhandler.h index b08f1f35b..31ea80c12 100644 --- a/linden/indra/newview/llfloaterhandler.h +++ b/linden/indra/newview/llfloaterhandler.h @@ -39,7 +39,7 @@ class LLFloaterHandler { public: LLFloaterHandler() : LLCommandHandler("floater", true) { } - bool handle(const LLSD& params, const LLSD& query_map, LLWebBrowserCtrl* web); + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web); }; #endif diff --git a/linden/indra/newview/llfloaterhtml.cpp b/linden/indra/newview/llfloaterhtml.cpp index a5d24f4d8..5822ed5b4 100644 --- a/linden/indra/newview/llfloaterhtml.cpp +++ b/linden/indra/newview/llfloaterhtml.cpp @@ -41,7 +41,6 @@ #include "llviewerwindow.h" #include "llweb.h" -#include "llwebbrowserctrl.h" LLFloaterHtml* LLFloaterHtml::sInstance = 0; diff --git a/linden/indra/newview/llfloaterhtmlhelp.cpp b/linden/indra/newview/llfloaterhtmlhelp.cpp deleted file mode 100644 index 17774030d..000000000 --- a/linden/indra/newview/llfloaterhtmlhelp.cpp +++ /dev/null @@ -1,562 +0,0 @@ -/** - * @file llfloaterhtmlhelp.cpp - * @brief HTML Help floater - uses embedded web browser control - * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloaterhtmlhelp.h" -#include "llfloaterhtml.h" - -#include "llchat.h" -#include "llfloaterchat.h" -#include "llparcel.h" -#include "lluictrlfactory.h" -#include "llwebbrowserctrl.h" -#include "llviewerwindow.h" -#include "llviewercontrol.h" -#include "llviewerparcelmgr.h" -#include "llweb.h" -#include "lltrans.h" -#include "llui.h" -#include "roles_constants.h" - -#include "llurlhistory.h" -#include "llwebbrowserctrl.h" -#include "llviewermedia.h" -#include "llviewerparcelmedia.h" -#include "llcombobox.h" - -#include "hippoGridManager.h" - -LLFloaterMediaBrowser::LLFloaterMediaBrowser(const LLSD& media_data) -{ - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_media_browser.xml"); -} - -void LLFloaterMediaBrowser::draw() -{ - BOOL url_exists = !mAddressCombo->getValue().asString().empty(); - childSetEnabled("go", url_exists); - childSetEnabled("set_home", url_exists); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if(parcel) - { - childSetVisible("parcel_owner_controls", LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_MEDIA)); - childSetEnabled("assign", !mAddressCombo->getValue().asString().empty()); - } - LLFloater::draw(); -} - -BOOL LLFloaterMediaBrowser::postBuild() -{ - mBrowser = getChild<LLWebBrowserCtrl>("browser"); - mBrowser->addObserver(this); - - mAddressCombo = getChild<LLComboBox>("address"); - mAddressCombo->setCommitCallback(onEnterAddress); - mAddressCombo->setCallbackUserData(this); - - childSetAction("back", onClickBack, this); - childSetAction("forward", onClickForward, this); - childSetAction("reload", onClickRefresh, this); - childSetAction("go", onClickGo, this); - childSetAction("close", onClickClose, this); - childSetAction("open_browser", onClickOpenWebBrowser, this); - childSetAction("assign", onClickAssign, this); - childSetAction("home", onClickHome, this); - childSetAction("set_home", onClickSetHome, this); - - buildURLHistory(); - - //Show home url if new session, last visited if not - std::string last_url = gSavedSettings.getString("BrowserLastVisited"); - if (last_url.empty()) - { - last_url = gSavedSettings.getString("BrowserHome"); - } - openMedia(last_url); - - return TRUE; -} - -void LLFloaterMediaBrowser::buildURLHistory() -{ - LLCtrlListInterface* url_list = childGetListInterface("address"); - if (url_list) - { - url_list->operateOnAll(LLCtrlListInterface::OP_DELETE); - } - - // Get all of the entries in the "parcel" collection - LLSD parcel_history = LLURLHistory::getURLHistory("browser"); - - LLSD::array_iterator iter_history = - parcel_history.beginArray(); - LLSD::array_iterator end_history = - parcel_history.endArray(); - for(; iter_history != end_history; ++iter_history) - { - std::string url = (*iter_history).asString(); - if(! url.empty()) - url_list->addSimpleElement(url); - } -} - -void LLFloaterMediaBrowser::onClose(bool app_quitting) -{ - //setVisible(FALSE); - destroy(); -} - -void LLFloaterMediaBrowser::onLocationChange( const EventType& eventIn ) -{ - // hitting the refresh button will navigate to same URL, so don't add to address history - mCurrentURL = eventIn.getStringValue(); - std::string::size_type string_start = mCurrentURL.find("://"); - std::string truncated_url; - if ((string_start == std::string::npos) || (1)) // NOTE: this conditional is forced true to disable truncation DEV-9834 - { - truncated_url = mCurrentURL; - } - else - { - truncated_url = mCurrentURL.substr(string_start + 3); - } - // redirects will navigate momentarily to about:blank, don't add to history - if (truncated_url != "about:blank") - { - mAddressCombo->remove(truncated_url); - mAddressCombo->add(truncated_url, ADD_SORTED); - mAddressCombo->selectByValue(truncated_url); - - // Serialize url history - LLURLHistory::removeURL("browser", truncated_url); - LLURLHistory::addURL("browser", truncated_url); - } - childSetEnabled("back", mBrowser->canNavigateBack()); - childSetEnabled("forward", mBrowser->canNavigateForward()); - childSetEnabled("reload", TRUE); - gSavedSettings.setString("BrowserLastVisited", truncated_url); -} - -//static -void LLFloaterMediaBrowser::helpF1() -{ - std::string url = gSavedSettings.getString("HelpSupportURL"); - LLSD payload; - payload["url"] = url; - - LLNotifications::instance().add("ClickOpenF1Help", LLSD(), payload, onClickF1HelpLoadURL); -} - -// static -bool LLFloaterMediaBrowser::onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0) - { - LLWeb::loadURL(notification["payload"]["url"].asString()); - } - return false; -} - -//static -void LLFloaterMediaBrowser::onEnterAddress(LLUICtrl* ctrl, void* user_data) -{ - LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; - self->mBrowser->navigateTo(self->mAddressCombo->getValue().asString()); -} - -//static -void LLFloaterMediaBrowser::onClickRefresh(void* user_data) -{ - LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; - - self->mAddressCombo->remove(0); - self->mBrowser->navigateTo(self->mCurrentURL); -} - -//static -void LLFloaterMediaBrowser::onClickForward(void* user_data) -{ - LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; - - self->mBrowser->navigateForward(); -} - -//static -void LLFloaterMediaBrowser::onClickBack(void* user_data) -{ - LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; - - self->mBrowser->navigateBack(); -} - -//static -void LLFloaterMediaBrowser::onClickGo(void* user_data) -{ - LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; - - self->mBrowser->navigateTo(self->mAddressCombo->getValue().asString()); -} - -//static -void LLFloaterMediaBrowser::onClickClose(void* user_data) -{ - LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; - - self->close(); -} - -//static -void LLFloaterMediaBrowser::onClickOpenWebBrowser(void* user_data) -{ - LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; - - std::string url = self->mCurrentURL.empty() ? - self->mBrowser->getHomePageUrl() : - self->mCurrentURL; - LLWeb::loadURLExternal(url); -} - -void LLFloaterMediaBrowser::onClickAssign(void* user_data) -{ - LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (!parcel) - { - return; - } - std::string media_url = self->mAddressCombo->getValue().asString(); - LLStringUtil::trim(media_url); - - parcel->setMediaURL(media_url); - parcel->setMediaType(std::string("text/html")); - - // Send current parcel data upstream to server - LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel, true ); - // now check for video - LLViewerParcelMedia::update( parcel ); -} - -// static -void LLFloaterMediaBrowser::onClickHome(void* user_data) -{ - LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; - if (self) - { - if (self->mBrowser) - { - std::string home_url = gSavedSettings.getString("BrowserHome"); - self->mBrowser->navigateTo(home_url); - } - } -} - -void LLFloaterMediaBrowser::onClickSetHome(void* user_data) -{ - LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; - std::string url = self->mCurrentURL; - if(!url.empty()) - { - LLChat chat; - std::string log_message = LLTrans::getString("new_home_page") + " "; - log_message += url; - chat.mText = log_message; - LLFloaterChat::addChat(chat, FALSE, FALSE); - gSavedSettings.setString("BrowserHome", url); - } -} - -void LLFloaterMediaBrowser::openMedia(const std::string& media_url) -{ - mBrowser->setHomePageUrl(media_url); - mBrowser->navigateTo(media_url); -} - -LLViewerHtmlHelp gViewerHtmlHelp; - -class LLFloaterHtmlHelp : - public LLFloater, - public LLWebBrowserCtrlObserver -{ -public: - LLFloaterHtmlHelp(std::string start_url, std::string title); - virtual ~LLFloaterHtmlHelp(); - - virtual void onClose( bool app_quitting ); - virtual void draw(); - - static void show(std::string url, std::string title); - -private: - static void onClickBack( void* data ); - //static void onClickHome( void* data ); - static void onClickForward( void* data ); - static void onClickClose( void* data ); - - // browser observer impls - virtual void onStatusTextChange( const EventType& eventIn ); - virtual void onLocationChange( const EventType& eventIn ); - - // used for some stats logging - will be removed at some point - static BOOL sFloaterOpened; - - static bool onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response); - - LLWebBrowserCtrl* mWebBrowser; - static LLFloaterHtmlHelp* sInstance; - LLButton* mBackButton; - LLButton* mForwardButton; - LLButton* mCloseButton; - LLTextBox* mStatusText; - std::string mStatusTextContents; - std::string mCurrentUrl; - std::string mSupportUrl; -}; - -LLFloaterHtmlHelp* LLFloaterHtmlHelp::sInstance = 0; - -BOOL LLFloaterHtmlHelp::sFloaterOpened = FALSE; - -//////////////////////////////////////////////////////////////////////////////// -// -LLFloaterHtmlHelp::LLFloaterHtmlHelp(std::string start_url, std::string title) -: LLFloater( std::string("HTML Help") ), - mWebBrowser( 0 ), - mStatusTextContents( LLStringUtil::null ), - mCurrentUrl( LLStringUtil::null ) -{ - sInstance = this; - - // create floater from its XML definition - LLUICtrlFactory::getInstance()->buildFloater( this, "floater_html_help.xml" ); - - childSetAction("back_btn", onClickBack, this); - //childSetAction("home_btn", onClickHome, this); - childSetAction("forward_btn", onClickForward, this); - - if (!title.empty()) - { - setTitle(title); - } - - mWebBrowser = getChild<LLWebBrowserCtrl>("html_help_browser" ); - if ( mWebBrowser ) - { - // observe browser control events - mWebBrowser->addObserver( this ); - - if (start_url != "") - { - mWebBrowser->navigateTo( start_url ); - } - else - { - // if the last page we were at before the client was closed is valid, go there and - // override what is in the XML file - // (not when the window was closed - it's only ever hidden - not closed) - std::string lastPageUrl = gSavedSettings.getString( "HtmlHelpLastPage" ); - if ( lastPageUrl != "" ) - { - mWebBrowser->navigateTo( lastPageUrl ); - }; - } - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// -LLFloaterHtmlHelp::~LLFloaterHtmlHelp() -{ - // stop observing browser events - if ( mWebBrowser ) - { - mWebBrowser->remObserver( this ); - }; - - // save position of floater - gSavedSettings.setRect( "HtmlHelpRect", getRect() ); - - // save the location we were at when SL closed - gSavedSettings.setString( "HtmlHelpLastPage", mCurrentUrl ); - - sInstance = 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLFloaterHtmlHelp::draw() -{ - // enable/disable buttons depending on state - if ( mWebBrowser ) - { - bool enable_back = mWebBrowser->canNavigateBack(); - childSetEnabled( "back_btn", enable_back ); - - bool enable_forward = mWebBrowser->canNavigateForward(); - childSetEnabled( "forward_btn", enable_forward ); - }; - - LLFloater::draw(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLFloaterHtmlHelp::show(std::string url, std::string title) -{ - LLFloaterHtml* floater_html = LLFloaterHtml::getInstance(); - floater_html->setVisible(FALSE); - - url = gHippoGridManager->getConnectedGrid()->getSupportUrl(); - if (!url.empty()) - { - if (gSavedSettings.getBOOL("UseExternalBrowser")) - { - LLSD payload; - payload["url"] = url; - LLNotifications::instance().add("ClickOpenF1Help", LLSD(), payload, onClickF1HelpLoadURL); - } - else - { - // don't wait, just do it - LLWeb::loadURLInternal(url); - } - } - else - { - LLNotifications::instance().add("NoSupportUrl"); - } -} - -// static -bool LLFloaterHtmlHelp::onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0) - { - const std::string& url = notification["payload"]["url"].asString(); - if (!url.empty()) - { - LLWeb::loadURLExternal(url); - } - else - { - llwarns << "Support URL not available." << llendl; - } - } - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLFloaterHtmlHelp::onClose( bool app_quitting ) -{ - setVisible( false ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLFloaterHtmlHelp::onClickClose( void* data ) -{ - LLFloaterHtmlHelp* self = ( LLFloaterHtmlHelp* )data; - - self->setVisible( false ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLFloaterHtmlHelp::onClickBack( void* data ) -{ - LLFloaterHtmlHelp* self = ( LLFloaterHtmlHelp* )data; - if ( self ) - { - if ( self->mWebBrowser ) - { - self->mWebBrowser->navigateBack(); - }; - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLFloaterHtmlHelp::onClickForward( void* data ) -{ - LLFloaterHtmlHelp* self = ( LLFloaterHtmlHelp* )data; - if ( self ) - { - if ( self->mWebBrowser ) - { - self->mWebBrowser->navigateForward(); - }; - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLFloaterHtmlHelp::onStatusTextChange( const EventType& eventIn ) -{ - mStatusTextContents = std::string( eventIn.getStringValue() ); - - childSetText("status_text", mStatusTextContents); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLFloaterHtmlHelp::onLocationChange( const EventType& eventIn ) -{ - llinfos << "MOZ> Location changed to " << eventIn.getStringValue() << llendl; - mCurrentUrl = std::string( eventIn.getStringValue() ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -LLViewerHtmlHelp::LLViewerHtmlHelp() -{ - LLUI::setHtmlHelp(this); -} - -LLViewerHtmlHelp::~LLViewerHtmlHelp() -{ - LLUI::setHtmlHelp(NULL); -} - -void LLViewerHtmlHelp::show() -{ - LLFloaterHtmlHelp::show("", ""); -} - -void LLViewerHtmlHelp::show(std::string url) -{ - std::string title; // empty - LLFloaterHtmlHelp::show(url, title); -} diff --git a/linden/indra/newview/llfloaterhtmlsimple.cpp b/linden/indra/newview/llfloaterhtmlsimple.cpp index 7dfc4f638..8091c1e97 100644 --- a/linden/indra/newview/llfloaterhtmlsimple.cpp +++ b/linden/indra/newview/llfloaterhtmlsimple.cpp @@ -35,7 +35,7 @@ #include "llfloaterhtmlsimple.h" #include "lluictrlfactory.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" LLFloaterHtmlSimple::LLFloaterHtmlSimple(const LLSD &initial_url) @@ -56,12 +56,12 @@ LLFloaterHtmlSimple::~LLFloaterHtmlSimple() void LLFloaterHtmlSimple::navigateTo(const std::string &url) { - LLWebBrowserCtrl* web = getChild<LLWebBrowserCtrl>("browser"); + LLMediaCtrl* web = getChild<LLMediaCtrl>("browser"); web->navigateTo(url); } void LLFloaterHtmlSimple::setTrusted(bool trusted) { - LLWebBrowserCtrl* web = getChild<LLWebBrowserCtrl>("browser"); + LLMediaCtrl* web = getChild<LLMediaCtrl>("browser"); web->setTrusted(trusted); } diff --git a/linden/indra/newview/llfloaterhud.cpp b/linden/indra/newview/llfloaterhud.cpp index 9810bf100..6324b5656 100644 --- a/linden/indra/newview/llfloaterhud.cpp +++ b/linden/indra/newview/llfloaterhud.cpp @@ -36,7 +36,7 @@ // Viewer libs #include "llviewercontrol.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" #include "llalertdialog.h" // Linden libs @@ -74,7 +74,7 @@ LLFloaterHUD::LLFloaterHUD() reshape(saved_position_rect.getWidth(), saved_position_rect.getHeight(), FALSE); setRect(saved_position_rect); - mWebBrowser = getChild<LLWebBrowserCtrl>("floater_hud_browser" ); + mWebBrowser = getChild<LLMediaCtrl>("floater_hud_browser" ); if (mWebBrowser) { // Open links in internal browser diff --git a/linden/indra/newview/llfloaterhud.h b/linden/indra/newview/llfloaterhud.h index 2d58685b5..919ffefdb 100644 --- a/linden/indra/newview/llfloaterhud.h +++ b/linden/indra/newview/llfloaterhud.h @@ -35,7 +35,7 @@ #include "llfloater.h" -class LLWebBrowserCtrl; +class LLMediaCtrl; class LLFloaterHUD : public LLFloater { @@ -53,7 +53,7 @@ class LLFloaterHUD : public LLFloater /*virtual*/ ~LLFloaterHUD(); private: - LLWebBrowserCtrl* mWebBrowser; ///< the actual web browser control + LLMediaCtrl* mWebBrowser; ///< the actual web browser control static LLFloaterHUD* sInstance; }; diff --git a/linden/indra/newview/llfloaterimagepreview.cpp b/linden/indra/newview/llfloaterimagepreview.cpp index 8142869af..aa8a94faf 100644 --- a/linden/indra/newview/llfloaterimagepreview.cpp +++ b/linden/indra/newview/llfloaterimagepreview.cpp @@ -60,7 +60,7 @@ #include "llstring.h" #include "llviewercontrol.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #ifdef LL_DARWIN #include "llwindowmacosx-objc.h" diff --git a/linden/indra/newview/llfloaterland.cpp b/linden/indra/newview/llfloaterland.cpp index 7dd4f8dc0..a6f39cbfc 100644 --- a/linden/indra/newview/llfloaterland.cpp +++ b/linden/indra/newview/llfloaterland.cpp @@ -56,6 +56,7 @@ #include "lllineeditor.h" #include "llnamelistctrl.h" #include "llnotify.h" +#include "llpanellandaudio.h" #include "llpanellandmedia.h" #include "llradiogroup.h" #include "llscrolllistctrl.h" @@ -76,7 +77,7 @@ #include "llviewercontrol.h" #include "roles_constants.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // [RLVa:KB] #include "rlvhandler.h" @@ -208,6 +209,7 @@ LLFloaterLand::LLFloaterLand(const LLSD& seed) factory_map["land_covenant_panel"] = LLCallbackMap(createPanelLandCovenant, this); factory_map["land_objects_panel"] = LLCallbackMap(createPanelLandObjects, this); factory_map["land_options_panel"] = LLCallbackMap(createPanelLandOptions, this); + factory_map["land_audio_panel"] = LLCallbackMap(createPanelLandAudio, this); factory_map["land_media_panel"] = LLCallbackMap(createPanelLandMedia, this); factory_map["land_access_panel"] = LLCallbackMap(createPanelLandAccess, this); @@ -243,6 +245,7 @@ void LLFloaterLand::refresh() mPanelGeneral->refresh(); mPanelObjects->refresh(); mPanelOptions->refresh(); + mPanelAudio->refresh(); mPanelMedia->refresh(); mPanelAccess->refresh(); } @@ -281,6 +284,15 @@ void* LLFloaterLand::createPanelLandOptions(void* data) return self->mPanelOptions; } + +// static +void* LLFloaterLand::createPanelLandAudio(void* data) +{ + LLFloaterLand* self = (LLFloaterLand*)data; + self->mPanelAudio = new LLPanelLandAudio(self->mParcel); + return self->mPanelAudio; +} + // static void* LLFloaterLand::createPanelLandMedia(void* data) { diff --git a/linden/indra/newview/llfloaterland.h b/linden/indra/newview/llfloaterland.h index 113b679d7..f8968a783 100644 --- a/linden/indra/newview/llfloaterland.h +++ b/linden/indra/newview/llfloaterland.h @@ -64,6 +64,7 @@ class LLParcelSelection; class LLPanelLandGeneral; class LLPanelLandObjects; class LLPanelLandOptions; +class LLPanelLandAudio; class LLPanelLandMedia; class LLPanelLandAccess; class LLPanelLandBan; @@ -102,6 +103,7 @@ class LLFloaterLand static void* createPanelLandCovenant(void* data); static void* createPanelLandObjects(void* data); static void* createPanelLandOptions(void* data); + static void* createPanelLandAudio(void* data); static void* createPanelLandMedia(void* data); static void* createPanelLandAccess(void* data); static void* createPanelLandBan(void* data); @@ -115,6 +117,7 @@ class LLFloaterLand LLPanelLandGeneral* mPanelGeneral; LLPanelLandObjects* mPanelObjects; LLPanelLandOptions* mPanelOptions; + LLPanelLandAudio* mPanelAudio; LLPanelLandMedia* mPanelMedia; LLPanelLandAccess* mPanelAccess; LLPanelLandCovenant* mPanelCovenant; diff --git a/linden/indra/newview/llfloatermap.cpp b/linden/indra/newview/llfloatermap.cpp index c15678d48..e63ea4b94 100644 --- a/linden/indra/newview/llfloatermap.cpp +++ b/linden/indra/newview/llfloatermap.cpp @@ -44,6 +44,7 @@ #include "lluictrlfactory.h" #include "llfirstuse.h" #include "panelradar.h" +#include "hippolimits.h" // [RLVa:KB] @@ -149,7 +150,7 @@ void LLFloaterMap::draw() drawChild(mPanelRadar); } } - else + else if (gHippoLimits->mAllowMinimap) //Check for if minimap is blocked { setMouseOpaque(TRUE); getDragHandle()->setMouseOpaque(TRUE); @@ -215,7 +216,6 @@ void LLFloaterMap::setRadarButtonState( bool showing_radar ) } } - void LLFloaterMap::adjustLayout( bool expand ) { S32 radar_height = mPanelRadar->getRect().getHeight(); diff --git a/linden/indra/newview/llfloatermediabrowser.cpp b/linden/indra/newview/llfloatermediabrowser.cpp new file mode 100644 index 000000000..d658a1158 --- /dev/null +++ b/linden/indra/newview/llfloatermediabrowser.cpp @@ -0,0 +1,437 @@ +/** + * @file llfloaterhtmlhelp.cpp + * @brief HTML Help floater - uses embedded web browser control + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloatermediabrowser.h" +#include "llfloaterhtml.h" + +#include "llchat.h" +#include "llfloaterchat.h" +#include "llparcel.h" +#include "llpluginclassmedia.h" +#include "lluictrlfactory.h" +#include "llmediactrl.h" +#include "llviewerwindow.h" +#include "llviewercontrol.h" +#include "llviewerparcelmgr.h" +#include "llweb.h" +#include "lltrans.h" +#include "llui.h" +#include "roles_constants.h" + +#include "llurlhistory.h" +#include "llmediactrl.h" +#include "llviewermedia.h" +#include "llviewerparcelmedia.h" +#include "llcombobox.h" + + +// TEMP +#include "llsdutil.h" + +LLFloaterMediaBrowser::LLFloaterMediaBrowser(const LLSD& media_data) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_media_browser.xml"); + +} + +void LLFloaterMediaBrowser::draw() +{ + BOOL url_exists = !mAddressCombo->getValue().asString().empty(); + childSetEnabled("go", url_exists); + childSetEnabled("set_home", url_exists); + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if(parcel) + { + childSetVisible("parcel_owner_controls", LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_MEDIA)); + childSetEnabled("assign", url_exists); + } + bool show_time_controls = false; + bool media_playing = false; + if(mBrowser) + { + LLPluginClassMedia* media_plugin = mBrowser->getMediaPlugin(); + if(media_plugin) + { + show_time_controls = media_plugin->pluginSupportsMediaTime(); + media_playing = media_plugin->getStatus() == LLPluginClassMediaOwner::MEDIA_PLAYING; + } + } + childSetVisible("rewind", show_time_controls); + childSetVisible("play", show_time_controls && ! media_playing); + childSetVisible("pause", show_time_controls && media_playing); + childSetVisible("stop", show_time_controls); + childSetVisible("seek", show_time_controls); + + childSetEnabled("play", ! media_playing); + childSetEnabled("stop", media_playing); + + childSetEnabled("back", mBrowser->canNavigateBack()); + childSetEnabled("forward", mBrowser->canNavigateForward()); + + LLFloater::draw(); +} + +BOOL LLFloaterMediaBrowser::postBuild() +{ + mBrowser = getChild<LLMediaCtrl>("browser"); + mBrowser->addObserver(this); + + mAddressCombo = getChild<LLComboBox>("address"); + mAddressCombo->setCommitCallback(onEnterAddress); + mAddressCombo->setCallbackUserData(this); + + childSetAction("back", onClickBack, this); + childSetAction("forward", onClickForward, this); + childSetAction("reload", onClickRefresh, this); + childSetAction("rewind", onClickRewind, this); + childSetAction("play", onClickPlay, this); + childSetAction("stop", onClickStop, this); + childSetAction("pause", onClickPlay, this); + childSetAction("seek", onClickSeek, this); + childSetAction("go", onClickGo, this); + childSetAction("close", onClickClose, this); + childSetAction("open_browser", onClickOpenWebBrowser, this); + childSetAction("assign", onClickAssign, this); + childSetAction("home", onClickHome, this); + childSetAction("set_home", onClickSetHome, this); + + buildURLHistory(); + + return TRUE; +} + +void LLFloaterMediaBrowser::buildURLHistory() +{ + LLCtrlListInterface* url_list = childGetListInterface("address"); + if (url_list) + { + url_list->operateOnAll(LLCtrlListInterface::OP_DELETE); + } + + // Get all of the entries in the "browser" collection + LLSD browser_history = LLURLHistory::getURLHistory("browser"); + + LLSD::array_iterator iter_history = + browser_history.beginArray(); + LLSD::array_iterator end_history = + browser_history.endArray(); + for(; iter_history != end_history; ++iter_history) + { + std::string url = (*iter_history).asString(); + if(! url.empty()) + url_list->addSimpleElement(url); + } + + // initialize URL history in the plugin + mBrowser->getMediaPlugin()->initializeUrlHistory(browser_history); +} + +std::string LLFloaterMediaBrowser::getSupportURL() +{ + return getString("support_page_url"); +} +void LLFloaterMediaBrowser::onClose(bool app_quitting) +{ + //setVisible(FALSE); + destroy(); +} + +void LLFloaterMediaBrowser::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + if(event == MEDIA_EVENT_LOCATION_CHANGED) + { + setCurrentURL(self->getLocation()); + } + else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) + { + // This is the event these flags are sent with. + childSetEnabled("back", self->getHistoryBackAvailable()); + childSetEnabled("forward", self->getHistoryForwardAvailable()); + } +} +void LLFloaterMediaBrowser::setCurrentURL(const std::string& url) +{ + mCurrentURL = url; + + // redirects will navigate momentarily to about:blank, don't add to history + if (mCurrentURL != "about:blank") + { + mAddressCombo->remove(mCurrentURL); + mAddressCombo->add(mCurrentURL, ADD_SORTED); + mAddressCombo->selectByValue(mCurrentURL); + + // Serialize url history + LLURLHistory::removeURL("browser", mCurrentURL); + LLURLHistory::addURL("browser", mCurrentURL); + } + childSetEnabled("back", mBrowser->canNavigateBack()); + childSetEnabled("forward", mBrowser->canNavigateForward()); + childSetEnabled("reload", TRUE); +} + +LLFloaterMediaBrowser* LLFloaterMediaBrowser::showInstance(const LLSD& media_url) +{ + LLFloaterMediaBrowser* floaterp = LLUISingleton<LLFloaterMediaBrowser, VisibilityPolicy<LLFloater> >::showInstance(media_url); + + floaterp->openMedia(media_url.asString()); + return floaterp; +} + +//static +void LLFloaterMediaBrowser::onEnterAddress(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + self->mBrowser->navigateTo(self->mAddressCombo->getValue().asString()); +} + +//static +void LLFloaterMediaBrowser::onClickRefresh(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + self->mAddressCombo->remove(0); + self->mBrowser->navigateTo(self->mCurrentURL); +} + +//static +void LLFloaterMediaBrowser::onClickForward(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + self->mBrowser->navigateForward(); +} + +//static +void LLFloaterMediaBrowser::onClickBack(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + self->mBrowser->navigateBack(); +} + +//static +void LLFloaterMediaBrowser::onClickGo(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + self->mBrowser->navigateTo(self->mAddressCombo->getValue().asString()); +} + +//static +void LLFloaterMediaBrowser::onClickClose(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + self->close(); +} + +//static +void LLFloaterMediaBrowser::onClickOpenWebBrowser(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + std::string url = self->mCurrentURL.empty() ? + self->mBrowser->getHomePageUrl() : + self->mCurrentURL; + LLWeb::loadURLExternal(url); +} + +void LLFloaterMediaBrowser::onClickAssign(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (!parcel) + { + return; + } + std::string media_url = self->mAddressCombo->getValue().asString(); + LLStringUtil::trim(media_url); + + if(parcel->getMediaType() != "text/html") + { + parcel->setMediaURL(media_url); + parcel->setMediaCurrentURL(media_url); + parcel->setMediaType(std::string("text/html")); + LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel, true ); + LLViewerParcelMedia::sendMediaNavigateMessage(media_url); + LLViewerParcelMedia::stop(); + // LLViewerParcelMedia::update( parcel ); + } + LLViewerParcelMedia::sendMediaNavigateMessage(media_url); +} + +// static +void LLFloaterMediaBrowser::onClickHome(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + if (self) + { + if (self->mBrowser) + { + std::string home_url = gSavedSettings.getString("BrowserHome"); + self->mBrowser->navigateTo(home_url); + } + } +} + +// static +void LLFloaterMediaBrowser::onClickSetHome(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + std::string url = self->mCurrentURL; + if(!url.empty()) + { + LLChat chat; + std::string log_message = LLTrans::getString("new_home_page") + " "; + log_message += url; + chat.mText = log_message; + LLFloaterChat::addChat(chat, FALSE, FALSE); + gSavedSettings.setString("BrowserHome", url); + } +} + +//static +void LLFloaterMediaBrowser::onClickRewind(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + if(self->mBrowser->getMediaPlugin()) + self->mBrowser->getMediaPlugin()->start(-2.0f); +} +//static +void LLFloaterMediaBrowser::onClickPlay(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + LLPluginClassMedia* plugin = self->mBrowser->getMediaPlugin(); + if(plugin) + { + if(plugin->getStatus() == LLPluginClassMediaOwner::MEDIA_PLAYING) + { + plugin->pause(); + } + else + { + plugin->start(); + } + } +} +//static +void LLFloaterMediaBrowser::onClickStop(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + if(self->mBrowser->getMediaPlugin()) + self->mBrowser->getMediaPlugin()->stop(); +} +//static +void LLFloaterMediaBrowser::onClickSeek(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + if(self->mBrowser->getMediaPlugin()) + self->mBrowser->getMediaPlugin()->start(2.0f); +} +void LLFloaterMediaBrowser::openMedia(const std::string& media_url) +{ + mBrowser->setHomePageUrl(media_url); + mBrowser->navigateTo(media_url); + setCurrentURL(media_url); +} +//////////////////////////////////////////////////////////////////////////////// +// + +LLViewerHtmlHelp gViewerHtmlHelp; + + +//////////////////////////////////////////////////////////////////////////////// +// +LLViewerHtmlHelp::LLViewerHtmlHelp() +{ + + LLUI::setHtmlHelp(this); +} + +LLViewerHtmlHelp::~LLViewerHtmlHelp() +{ + + LLUI::setHtmlHelp(NULL); +} + +void LLViewerHtmlHelp::show() +{ + show(""); +} + +void LLViewerHtmlHelp::show(std::string url) +{ + LLFloaterMediaBrowser* floater_html = LLFloaterMediaBrowser::getInstance(); + floater_html->setVisible(FALSE); + + if (url.empty()) + { + url = floater_html->getSupportURL(); + } + + if (gSavedSettings.getBOOL("UseExternalBrowser")) + { + LLSD notificationData; + notificationData["url"] = url; + + LLNotifications::instance().add("ClickOpenF1Help", notificationData, LLSD(), onClickF1HelpLoadURL); + floater_html->close(); + } + else + { + // don't wait, just do it + floater_html->setVisible(TRUE); + floater_html->openMedia(url); + } +} +// static +bool LLViewerHtmlHelp::onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response) +{ + LLFloaterMediaBrowser* floater_html = LLFloaterMediaBrowser::getInstance(); + floater_html->setVisible(FALSE); + std::string url = floater_html->getSupportURL(); + S32 option = LLNotification::getSelectedOption(notification, response); + if (option == 0) + { + LLWeb::loadURL(url); + } + floater_html->close(); + return false; +} + diff --git a/linden/indra/newview/llfloaterhtmlhelp.h b/linden/indra/newview/llfloatermediabrowser.h similarity index 78% rename from linden/indra/newview/llfloaterhtmlhelp.h rename to linden/indra/newview/llfloatermediabrowser.h index 83f15cdaf..7de190064 100644 --- a/linden/indra/newview/llfloaterhtmlhelp.h +++ b/linden/indra/newview/llfloatermediabrowser.h @@ -35,7 +35,7 @@ #include "llhtmlhelp.h" #include "llfloater.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" class LLViewerHtmlHelp : public LLHtmlHelp { @@ -45,28 +45,38 @@ class LLViewerHtmlHelp : public LLHtmlHelp /*virtual*/ void show(); /*virtual*/ void show(std::string start_url); + void show(std::string start_url, std::string title); + + static bool onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response); + }; class LLComboBox; -class LLWebBrowserCtrl; +class LLMediaCtrl; -class LLFloaterMediaBrowser : public LLFloater, public LLFloaterSingleton<LLFloaterMediaBrowser>, public LLWebBrowserCtrlObserver +class LLFloaterMediaBrowser : + public LLFloater, + public LLUISingleton<LLFloaterMediaBrowser, + VisibilityPolicy<LLFloater> >, + public LLViewerMediaObserver { public: LLFloaterMediaBrowser(const LLSD& media_data); /*virtual*/ BOOL postBuild(); /*virtual*/ void onClose(bool app_quitting); - /*virtual*/ void onLocationChange( const EventType& eventIn ); - /*virtual*/ void draw(); + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + void openMedia(const std::string& media_url); void buildURLHistory(); + std::string getSupportURL(); + void setCurrentURL(const std::string& url); - static void helpF1(); -private: + static LLFloaterMediaBrowser* showInstance(const LLSD& id); static void onEnterAddress(LLUICtrl* ctrl, void* user_data); static void onClickRefresh(void* user_data); static void onClickBack(void* user_data); @@ -77,9 +87,13 @@ class LLFloaterMediaBrowser : public LLFloater, public LLFloaterSingleton<LLFloa static void onClickAssign(void* user_data); static void onClickHome(void* user_data); static void onClickSetHome(void* user_data); - static bool onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response); + static void onClickRewind(void* user_data); + static void onClickPlay(void* user_data); + static void onClickStop(void* user_data); + static void onClickSeek(void* user_data); - LLWebBrowserCtrl* mBrowser; +private: + LLMediaCtrl* mBrowser; LLComboBox* mAddressCombo; std::string mCurrentURL; }; diff --git a/linden/indra/newview/llfloatermessagebuilder.cpp b/linden/indra/newview/llfloatermessagebuilder.cpp new file mode 100644 index 000000000..90c0f9ee1 --- /dev/null +++ b/linden/indra/newview/llfloatermessagebuilder.cpp @@ -0,0 +1,978 @@ +// <edit> +#include "llviewerprecompiledheaders.h" +#include "llfloatermessagebuilder.h" +#include "lluictrlfactory.h" +#include "llmessagetemplate.h" +#include "llagent.h" +#include "llchat.h" +#include "llfloaterchat.h" +#include "llviewerregion.h" // getHandle +#include "llcombobox.h" +#include "llselectmgr.h" // fill in stuff about selected object +#include "llparcel.h" +#include "llviewerparcelmgr.h" // same for parcel +#include "llscrolllistctrl.h" +#include "llworld.h" +#include "lltemplatemessagebuilder.h" + +//////////////////////////////// +// LLNetListItem +//////////////////////////////// +LLNetListItem::LLNetListItem(LLUUID id) +: mID(id), + mAutoName(TRUE), + mName("No name"), + mPreviousRegionName(""), + mCircuitData(NULL) +{ +} + +//////////////////////////////// +// LLFloaterMessageBuilder +//////////////////////////////// +std::list<LLNetListItem*> LLFloaterMessageBuilder::sNetListItems; + +LLFloaterMessageBuilder::LLFloaterMessageBuilder(std::string initial_text) +: LLFloater(), + LLEventTimer(1.0f), + mNetInfoMode(NI_NET), + mInitialText(initial_text) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_message_builder.xml"); +} +LLFloaterMessageBuilder::~LLFloaterMessageBuilder() +{ +} +void LLFloaterMessageBuilder::show(std::string initial_text) +{ + (new LLFloaterMessageBuilder(initial_text))->open(); +} +BOOL LLFloaterMessageBuilder::tick() +{ + refreshNetList(); + return FALSE; +} +LLNetListItem* LLFloaterMessageBuilder::findNetListItem(LLHost host) +{ + std::list<LLNetListItem*>::iterator end = sNetListItems.end(); + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != end; ++iter) + if((*iter)->mCircuitData && (*iter)->mCircuitData->getHost() == host) + return (*iter); + return NULL; +} +LLNetListItem* LLFloaterMessageBuilder::findNetListItem(LLUUID id) +{ + std::list<LLNetListItem*>::iterator end = sNetListItems.end(); + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != end; ++iter) + if((*iter)->mID == id) + return (*iter); + return NULL; +} +void LLFloaterMessageBuilder::refreshNetList() +{ + LLScrollListCtrl* scrollp = getChild<LLScrollListCtrl>("net_list"); + // Update circuit data of net list items + std::vector<LLCircuitData*> circuits = gMessageSystem->getCircuit()->getCircuitDataList(); + std::vector<LLCircuitData*>::iterator circuits_end = circuits.end(); + for(std::vector<LLCircuitData*>::iterator iter = circuits.begin(); iter != circuits_end; ++iter) + { + LLNetListItem* itemp = findNetListItem((*iter)->getHost()); + if(!itemp) + { + LLUUID id; id.generate(); + itemp = new LLNetListItem(id); + sNetListItems.push_back(itemp); + } + itemp->mCircuitData = (*iter); + } + // Clear circuit data of items whose circuits are gone + std::list<LLNetListItem*>::iterator items_end = sNetListItems.end(); + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != items_end; ++iter) + { + if(std::find(circuits.begin(), circuits.end(), (*iter)->mCircuitData) == circuits.end()) + (*iter)->mCircuitData = NULL; + } + // Remove net list items that are totally useless now + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != sNetListItems.end();) + { + if((*iter)->mCircuitData == NULL) + iter = sNetListItems.erase(iter); + else ++iter; + } + // Update names of net list items + items_end = sNetListItems.end(); + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != items_end; ++iter) + { + LLNetListItem* itemp = (*iter); + if(itemp->mAutoName) + { + if(itemp->mCircuitData) + { + LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(itemp->mCircuitData->getHost()); + if(regionp) + { + std::string name = regionp->getName(); + if(name == "") name = llformat("%s (awaiting region name)", itemp->mCircuitData->getHost().getString().c_str()); + itemp->mName = name; + itemp->mPreviousRegionName = name; + } + else + { + itemp->mName = itemp->mCircuitData->getHost().getString(); + if(itemp->mPreviousRegionName != "") + itemp->mName.append(llformat(" (was %s)", itemp->mPreviousRegionName.c_str())); + } + } + else + { + // an item just for an event queue, not handled yet + itemp->mName = "Something else"; + } + } + } + // Rebuild scroll list from scratch + LLUUID selected_id = scrollp->getFirstSelected() ? scrollp->getFirstSelected()->getUUID() : LLUUID::null; + S32 scroll_pos = scrollp->getScrollPos(); + scrollp->clearRows(); + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != items_end; ++iter) + { + LLNetListItem* itemp = (*iter); + LLSD element; + element["id"] = itemp->mID; + LLSD& text_column = element["columns"][0]; + text_column["column"] = "text"; + text_column["value"] = itemp->mName + (itemp->mCircuitData->getHost() == gAgent.getRegionHost() ? " (main)" : ""); + + LLSD& state_column = element["columns"][ 1]; + state_column["column"] = "state"; + state_column["value"] = ""; + + LLScrollListItem* scroll_itemp = scrollp->addElement(element); + BOOL has_live_circuit = itemp->mCircuitData && itemp->mCircuitData->isAlive(); + + LLScrollListText* state = (LLScrollListText*)scroll_itemp->getColumn(1); + + if(has_live_circuit) + state->setText(std::string("Alive")); + else + state->setText(std::string("Alive")); + } + if(selected_id.notNull()) scrollp->selectByID(selected_id); + if(scroll_pos < scrollp->getItemCount()) scrollp->setScrollPos(scroll_pos); +} +BOOL LLFloaterMessageBuilder::postBuild() +{ + childSetText("message_edit", mInitialText); + childSetAction("send_btn", onClickSend, this); + std::vector<std::string> names; + LLComboBox* combo; + LLMessageSystem::message_template_name_map_t::iterator temp_end = gMessageSystem->mMessageTemplates.end(); + LLMessageSystem::message_template_name_map_t::iterator temp_iter; + std::vector<std::string>::iterator names_end; + std::vector<std::string>::iterator names_iter; + for(temp_iter = gMessageSystem->mMessageTemplates.begin(); temp_iter != temp_end; ++temp_iter) + if((*temp_iter).second->getTrust() == MT_NOTRUST) + names.push_back((*temp_iter).second->mName); + std::sort(names.begin(), names.end()); + combo = getChild<LLComboBox>("untrusted_message_combo"); + names_end = names.end(); + for(names_iter = names.begin(); names_iter != names_end; ++names_iter) + combo->add((*names_iter)); + names.clear(); + for(temp_iter = gMessageSystem->mMessageTemplates.begin(); temp_iter != temp_end; ++temp_iter) + if((*temp_iter).second->getTrust() == MT_TRUST) + names.push_back((*temp_iter).second->mName); + std::sort(names.begin(), names.end()); + combo = getChild<LLComboBox>("trusted_message_combo"); + names_end = names.end(); + for(names_iter = names.begin(); names_iter != names_end; ++names_iter) + combo->add((*names_iter)); + childSetCommitCallback("untrusted_message_combo", onCommitPacketCombo, this); + childSetCommitCallback("trusted_message_combo", onCommitPacketCombo, this); + return TRUE; +} +inline std::vector<std::string> split(std::string input, std::string separator) +{ + S32 size = input.length(); + char* buffer = new char[size + 1]; + strncpy(buffer, input.c_str(), size); + buffer[size] = '\0'; + std::vector<std::string> lines; + char* result = strtok(buffer, separator.c_str()); + while(result) + { + lines.push_back(result); + result = strtok(NULL, separator.c_str()); + } + delete[] buffer; + return lines; +} +std::string mvtstr(e_message_variable_type var_type) +{ + switch(var_type) + { + case MVT_U8: + return "U8"; + break; + case MVT_U16: + return "U16"; + break; + case MVT_U32: + return "U32"; + break; + case MVT_U64: + return "U64"; + break; + case MVT_S8: + return "S8"; + break; + case MVT_S16: + return "S16"; + break; + case MVT_S32: + return "S32"; + break; + case MVT_S64: + return "S64"; + break; + case MVT_F32: + return "F32"; + break; + case MVT_F64: + return "F64"; + break; + case MVT_LLVector3: + return "LLVector3"; + break; + case MVT_LLVector3d: + return "LLVector3d"; + break; + case MVT_LLVector4: + return "LLVector4"; + break; + case MVT_LLQuaternion: + return "LLQuaternion"; + break; + case MVT_LLUUID: + return "LLUUID"; + break; + case MVT_BOOL: + return "BOOL"; + break; + case MVT_IP_ADDR: + return "IPADDR"; + break; + case MVT_IP_PORT: + return "IPPORT"; + break; + case MVT_VARIABLE: + return "Variable"; + break; + case MVT_FIXED: + return "Fixed"; + break; + default: + return "Missingno."; + break; + } +} +// static +BOOL LLFloaterMessageBuilder::addField(e_message_variable_type var_type, const char* var_name, std::string input, BOOL hex) +{ + LLStringUtil::trim(input); + if(input.length() < 1 && var_type != MVT_VARIABLE) + return FALSE; + U8 valueU8; + U16 valueU16; + U32 valueU32; + U64 valueU64; + S8 valueS8; + S16 valueS16; + S32 valueS32; + // S64 valueS64; + F32 valueF32; + F64 valueF64; + LLVector3 valueVector3; + LLVector3d valueVector3d; + LLVector4 valueVector4; + LLQuaternion valueQuaternion; + LLUUID valueLLUUID; + BOOL valueBOOL; + std::string input_lower = input; + LLStringUtil::toLower(input_lower); + if(input_lower == "$agentid") + input = gAgent.getID().asString(); + else if(input_lower == "$sessionid") + input = gAgent.getSessionID().asString(); + else if(input_lower == "$uuid") + { + LLUUID id; + id.generate(); + input = id.asString(); + } + else if(input_lower == "$circuitcode") + { + std::stringstream temp_stream; + temp_stream << gMessageSystem->mOurCircuitCode; + input = temp_stream.str(); + } + else if(input_lower == "$regionhandle") + { + std::stringstream temp_stream; + temp_stream << (gAgent.getRegion() ? gAgent.getRegion()->getHandle() : 0); + input = temp_stream.str(); + } + else if(input_lower == "$position" || input_lower == "$pos") + { + std::stringstream temp_stream; + valueVector3 = gAgent.getPositionAgent(); + temp_stream << "<" << valueVector3[0] << ", " << valueVector3[1] << ", " << valueVector3[2] << ">"; + input = temp_stream.str(); + } + if(hex) + { + if(var_type != MVT_VARIABLE && var_type != MVT_FIXED) + return FALSE; + int len = input_lower.length(); + const char* cstr = input_lower.c_str(); + std::string new_input(""); + BOOL nibble = FALSE; + char byte = 0; + for(int i = 0; i < len; i++) + { + char c = cstr[i]; + if(c >= 0x30 && c <= 0x39) + c -= 0x30; + else if(c >= 0x61 && c <= 0x66) + c -= 0x57; + else if(c != 0x20) + return FALSE; + else + continue; + if(!nibble) + byte = c << 4; + else + new_input.push_back(byte | c); + nibble = !nibble; + } + if(nibble) + return FALSE; + input = new_input; + } + std::stringstream stream(input); + std::vector<std::string> tokens; + switch(var_type) + { + case MVT_U8: + if(input.substr(0, 1) == "-") + return FALSE; + if((stream >> valueU32).fail()) + return FALSE; + valueU8 = (U8)valueU32; + gMessageSystem->addU8(var_name, valueU8); + return TRUE; + break; + case MVT_U16: + if(input.substr(0, 1) == "-") + return FALSE; + if((stream >> valueU16).fail()) + return FALSE; + gMessageSystem->addU16(var_name, valueU16); + return TRUE; + break; + case MVT_U32: + if(input.substr(0, 1) == "-") + return FALSE; + if((stream >> valueU32).fail()) + return FALSE; + gMessageSystem->addU32(var_name, valueU32); + return TRUE; + break; + case MVT_U64: + if(input.substr(0, 1) == "-") + return FALSE; + if((stream >> valueU64).fail()) + return FALSE; + gMessageSystem->addU64(var_name, valueU64); + return TRUE; + break; + case MVT_S8: + if((stream >> valueS8).fail()) + return FALSE; + gMessageSystem->addS8(var_name, valueS8); + return TRUE; + break; + case MVT_S16: + if((stream >> valueS16).fail()) + return FALSE; + gMessageSystem->addS16(var_name, valueS16); + return TRUE; + break; + case MVT_S32: + if((stream >> valueS32).fail()) + return FALSE; + gMessageSystem->addS32(var_name, valueS32); + return TRUE; + break; + /* + case MVT_S64: + if((stream >> valueS64).fail()) + return FALSE; + gMessageSystem->addS64(var_name, valueS64); + return TRUE; + break; + */ + case MVT_F32: + if((stream >> valueF32).fail()) + return FALSE; + gMessageSystem->addF32(var_name, valueF32); + return TRUE; + break; + case MVT_F64: + if((stream >> valueF64).fail()) + return FALSE; + gMessageSystem->addF64(var_name, valueF64); + return TRUE; + break; + case MVT_LLVector3: + LLStringUtil::trim(input); + if(input.substr(0, 1) != "<" || input.substr(input.length() - 1, 1) != ">") + return FALSE; + tokens = split(input.substr(1, input.length() - 2), ","); + if(tokens.size() != 3) + return FALSE; + for(int i = 0; i < 3; i++) + { + stream.clear(); + stream.str(tokens[i]); + if((stream >> valueF32).fail()) + return FALSE; + valueVector3.mV[i] = valueF32; + } + gMessageSystem->addVector3(var_name, valueVector3); + return TRUE; + break; + case MVT_LLVector3d: + LLStringUtil::trim(input); + if(input.substr(0, 1) != "<" || input.substr(input.length() - 1, 1) != ">") + return FALSE; + tokens = split(input.substr(1, input.length() - 2), ","); + if(tokens.size() != 3) + return FALSE; + for(int i = 0; i < 3; i++) + { + stream.clear(); + stream.str(tokens[i]); + if((stream >> valueF64).fail()) + return FALSE; + valueVector3d.mdV[i] = valueF64; + } + gMessageSystem->addVector3d(var_name, valueVector3d); + return TRUE; + break; + case MVT_LLVector4: + LLStringUtil::trim(input); + if(input.substr(0, 1) != "<" || input.substr(input.length() - 1, 1) != ">") + return FALSE; + tokens = split(input.substr(1, input.length() - 2), ","); + if(tokens.size() != 4) + return FALSE; + for(int i = 0; i < 4; i++) + { + stream.clear(); + stream.str(tokens[i]); + if((stream >> valueF32).fail()) + return FALSE; + valueVector4.mV[i] = valueF32; + } + gMessageSystem->addVector4(var_name, valueVector4); + return TRUE; + break; + case MVT_LLQuaternion: + LLStringUtil::trim(input); + if(input.substr(0, 1) != "<" || input.substr(input.length() - 1, 1) != ">") + return FALSE; + tokens = split(input.substr(1, input.length() - 2), ","); + if(tokens.size() != 3) + return FALSE; + for(int i = 0; i < 3; i++) + { + stream.clear(); + stream.str(tokens[i]); + if((stream >> valueF32).fail()) + return FALSE; + valueVector3.mV[i] = valueF32; + } + valueQuaternion.unpackFromVector3(valueVector3); + gMessageSystem->addQuat(var_name, valueQuaternion); + return TRUE; + break; + case MVT_LLUUID: + if((stream >> valueLLUUID).fail()) + return FALSE; + gMessageSystem->addUUID(var_name, valueLLUUID); + return TRUE; + break; + case MVT_BOOL: + if(input_lower == "true") + valueBOOL = TRUE; + else if(input_lower == "false") + valueBOOL = FALSE; + else if((stream >> valueBOOL).fail()) + return FALSE; + //gMessageSystem->addBOOL(var_name, valueBOOL); + gMessageSystem->addU8(var_name, (U8)valueBOOL); + return TRUE; + break; + case MVT_IP_ADDR: + if((stream >> valueU32).fail()) + return FALSE; + gMessageSystem->addIPAddr(var_name, valueU32); + return TRUE; + break; + case MVT_IP_PORT: + if((stream >> valueU16).fail()) + return FALSE; + gMessageSystem->addIPPort(var_name, valueU16); + return TRUE; + break; + case MVT_VARIABLE: + if(!hex) + { + char* buffer = new char[input.size() + 1]; + strncpy(buffer, input.c_str(), input.size()); + buffer[input.size()] = '\0'; + gMessageSystem->addBinaryData(var_name, buffer, input.size() + 1); + delete[] buffer; + } + else + gMessageSystem->addBinaryData(var_name, input.c_str(), input.size()); + return TRUE; + break; + case MVT_FIXED: + if(!hex) + { + char* buffer = new char[input.size() + 1]; + strncpy(buffer, input.c_str(), input.size()); + buffer[input.size()] = '\0'; + gMessageSystem->addBinaryData(var_name, buffer, input.size()); + delete[] buffer; + } + else + gMessageSystem->addBinaryData(var_name, input.c_str(), input.size()); + return TRUE; + break; + default: + break; + } + return FALSE; +} +// static +void LLFloaterMessageBuilder::onCommitPacketCombo(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterMessageBuilder* floaterp = (LLFloaterMessageBuilder*)user_data; + LLViewerObject* selected_objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + LLParcel* agent_parcelp = LLViewerParcelMgr::getInstance()->getAgentParcel(); + std::string message = ctrl->getValue(); + std::map<const char *, LLMessageTemplate*>::iterator template_iter; + template_iter = gMessageSystem->mMessageTemplates.find( LLMessageStringTable::getInstance()->getString(message.c_str()) ); + if(template_iter == gMessageSystem->mMessageTemplates.end()) + { + floaterp->childSetText("message_edit", std::string("")); + return; + } + std::string text(llformat((*template_iter).second->getTrust() == MT_NOTRUST ? "out %s\n" : "in %s\n", message.c_str())); + LLMessageTemplate* temp = (*template_iter).second; + LLMessageTemplate::message_block_map_t::iterator blocks_end = temp->mMemberBlocks.end(); + for (LLMessageTemplate::message_block_map_t::iterator blocks_iter = temp->mMemberBlocks.begin(); + blocks_iter != blocks_end; ++blocks_iter) + { + LLMessageBlock* block = (*blocks_iter); + const char* block_name = block->mName; + std::string block_name_string = std::string(block_name); + S32 num_blocks = 1; + if(block->mType == MBT_MULTIPLE) + num_blocks = block->mNumber; + else if(("ObjectLink" == message && "ObjectData" == block_name_string)) + num_blocks = 2; + for(S32 i = 0; i < num_blocks; i++) + { + text.append(llformat("[%s]\n", block_name)); + LLMessageBlock::message_variable_map_t::iterator var_end = block->mMemberVariables.end(); + for (LLMessageBlock::message_variable_map_t::iterator var_iter = block->mMemberVariables.begin(); + var_iter != var_end; ++var_iter) + { + LLMessageVariable* variable = (*var_iter); + const char* var_name = variable->getName(); + std::string var_name_string = std::string(var_name); + text.append(llformat("%s = ", var_name)); + std::string value(""); + S32 size = variable->getSize(); + switch(variable->getType()) + { + case MVT_U8: + case MVT_U16: + case MVT_U32: + case MVT_U64: + case MVT_S8: + case MVT_S16: + case MVT_S32: + case MVT_IP_ADDR: + case MVT_IP_PORT: + if("RegionHandle" == var_name_string || "Handle" == var_name_string) + value = "$RegionHandle"; + else if("CircuitCode" == var_name_string || "ViewerCircuitCode" == var_name_string + || ("Code" == var_name_string && "CircuitCode" == block_name_string) ) + { + value = "$CircuitCode"; + } + else if(selected_objectp && + ( + "ObjectLocalID" == var_name_string + || "TaskLocalID" == var_name_string + || ("LocalID" == var_name_string && + ( + "ObjectData" == block_name_string + || "UpdateData" == block_name_string + || "InventoryData" == block_name_string + ) + ) + ) + ) + { + std::stringstream temp_stream; + temp_stream << selected_objectp->getLocalID(); + value = temp_stream.str(); + } + else if( agent_parcelp && + "LocalID" == var_name_string && + ( + "ParcelData" == block_name_string + || message.find("Parcel") != message.npos + ) + ) + { + std::stringstream temp_stream; + temp_stream << agent_parcelp->getLocalID(); + value = temp_stream.str(); + } + else if("PCode" == var_name_string) + value = "9"; + else if("PathCurve" == var_name_string) + value = "16"; + else if("ProfileCurve" == var_name_string) + value = "1"; + else if("PathScaleX" == var_name_string || "PathScaleY" == var_name_string) + value = "100"; + else if("BypassRaycast" == var_name_string) + value = "1"; + else + value = "0"; + break; + case MVT_F32: + case MVT_F64: + value = "0.0"; + break; + case MVT_LLVector3: + case MVT_LLVector3d: + case MVT_LLQuaternion: + if("Position" == var_name_string || "RayStart" == var_name_string || "RayEnd" == var_name_string) + value = "$Position"; + else if("Scale" == var_name_string) + value = "<0.5, 0.5, 0.5>"; + else + value = "<0, 0, 0>"; + break; + case MVT_LLVector4: + value = "<0, 0, 0, 0>"; + break; + case MVT_LLUUID: + if("AgentID" == var_name_string) + value = "$AgentID"; + else if("SessionID" == var_name_string) + value = "$SessionID"; + else if("ObjectID" == var_name_string && selected_objectp) + value = selected_objectp->getID().asString(); + else if("ParcelID" == var_name_string && agent_parcelp) + value = agent_parcelp->getID().asString(); + else + value = "00000000-0000-0000-0000-000000000000"; + break; + case MVT_BOOL: + value = "false"; + break; + case MVT_VARIABLE: + value = "Hello, world!"; + break; + case MVT_FIXED: + for(S32 si = 0; si < size; si++) + //value.append(std::string("0123456789abcdef").substr(si & 0xf, 1)); + value.append("a"); + break; + default: + value = ""; + break; + } + text.append(llformat("%s\n", value.c_str())); + } + } + } + text = text.substr(0, text.length() - 1); + floaterp->childSetText("message_edit", text); +} +// static +void LLFloaterMessageBuilder::onClickSend(void* user_data) +{ + LLFloaterMessageBuilder* floaterp = (LLFloaterMessageBuilder*)user_data; + std::vector<std::string> lines = split(floaterp->childGetText("message_edit"), "\n"); + if(!lines.size()) + { + LLFloaterChat::addChat(LLChat("Not enough information :O")); + return; + } + std::vector<std::string> tokens = split(lines[0], " "); + if(!tokens.size()) + { + LLFloaterChat::addChat(LLChat("Not enough information :O")); + return; + } + std::string dir_str = tokens[0]; + LLStringUtil::toLower(dir_str); + // Direction + BOOL outgoing; + if(dir_str == "out") + outgoing = TRUE; + else if(dir_str == "in") + outgoing = FALSE; + else + { + LLFloaterChat::addChat(LLChat("Expected direction 'in' or 'out'")); + return; + } + // Message + std::string message = "Invalid"; + if(tokens.size() > 1) + { + if(tokens.size() > 2) + { + LLFloaterChat::addChat(LLChat("Unexpected extra stuff at the top")); + return; + } + message = tokens[1]; + LLStringUtil::trim(message); + } + // Body + std::vector<parts_block> parts; + if(lines.size() > 1) + { + std::vector<std::string>::iterator line_end = lines.end(); + std::vector<std::string>::iterator line_iter = lines.begin(); + ++line_iter; + std::string current_block(""); + int current_block_index = -1; + for( ; line_iter != line_end; ++line_iter) + { + std::string line = (*line_iter); + LLStringUtil::trim(line); + if(!line.length()) + continue; + if(line.substr(0, 1) == "[" && line.substr(line.size() - 1, 1) == "]") + { + current_block = line.substr(1, line.length() - 2); + LLStringUtil::trim(current_block); + ++current_block_index; + parts_block pb; + pb.name = current_block; + parts.push_back(pb); + } + else + { + if(current_block.empty()) + { + LLFloaterChat::addChat(LLChat("Unexpected field when no block yet")); + return; + } + int eqpos = line.find("="); + if(eqpos == line.npos) + { + LLFloaterChat::addChat(LLChat("Missing an equal sign")); + return; + } + std::string field = line.substr(0, eqpos); + LLStringUtil::trim(field); + if(!field.length()) + { + LLFloaterChat::addChat(LLChat("Missing name of field")); + return; + } + std::string value = line.substr(eqpos + 1); + LLStringUtil::trim(value); + parts_var pv; + if(value.substr(0, 1) == "|") + { + pv.hex = TRUE; + value = value.substr(1); + LLStringUtil::trim(value); + } + else + pv.hex = FALSE; + pv.name = field; + pv.value = value; + parts[current_block_index].vars.push_back(pv); + } + } + } + // Verification + std::map<const char *, LLMessageTemplate*>::iterator template_iter; + template_iter = gMessageSystem->mMessageTemplates.find( LLMessageStringTable::getInstance()->getString(message.c_str()) ); + if(template_iter == gMessageSystem->mMessageTemplates.end()) + { + LLFloaterChat::addChat(LLChat(llformat("Don't know how to build a '%s' message", message.c_str()))); + return; + } + LLMessageTemplate* temp = (*template_iter).second; + std::vector<parts_block>::iterator parts_end = parts.end(); + std::vector<parts_block>::iterator parts_iter = parts.begin(); + LLMessageTemplate::message_block_map_t::iterator blocks_end = temp->mMemberBlocks.end(); + for (LLMessageTemplate::message_block_map_t::iterator blocks_iter = temp->mMemberBlocks.begin(); + blocks_iter != blocks_end; ) + { + LLMessageBlock* block = (*blocks_iter); + const char* block_name = block->mName; + if(parts_iter == parts_end) + { + if(block->mType != MBT_VARIABLE) + LLFloaterChat::addChat(LLChat(llformat("Expected '%s' block", block_name))); + else + { + ++blocks_iter; + continue; + } + return; + } + else if((*parts_iter).name != block_name) + { + if(block->mType != MBT_VARIABLE) + LLFloaterChat::addChat(LLChat(llformat("Expected '%s' block", block_name))); + else + { + ++blocks_iter; + continue; + } + return; + } + std::vector<parts_var>::iterator part_var_end = (*parts_iter).vars.end(); + std::vector<parts_var>::iterator part_var_iter = (*parts_iter).vars.begin(); + LLMessageBlock::message_variable_map_t::iterator var_end = block->mMemberVariables.end(); + for (LLMessageBlock::message_variable_map_t::iterator var_iter = block->mMemberVariables.begin(); + var_iter != var_end; ++var_iter) + { + LLMessageVariable* variable = (*var_iter); + const char* var_name = variable->getName(); + if(part_var_iter == part_var_end) + { + LLFloaterChat::addChat(LLChat(llformat("Expected '%s' field under '%s' block", var_name, block_name))); + return; + } + else if((*part_var_iter).name != var_name) + { + LLFloaterChat::addChat(LLChat(llformat("Expected '%s' field under '%s' block", var_name, block_name))); + return; + } + (*part_var_iter).var_type = variable->getType(); + ++part_var_iter; + } + if(part_var_iter != part_var_end) + { + LLFloaterChat::addChat(LLChat(llformat("Unexpected field(s) at end of '%s' block", block_name))); + return; + } + ++parts_iter; + // test + if((block->mType != MBT_SINGLE) && (parts_iter != parts_end) && ((*parts_iter).name == block_name)) + { + // block will repeat + } + else ++blocks_iter; + } + if(parts_iter != parts_end) + { + LLFloaterChat::addChat(LLChat("Unexpected block(s) at end")); + return; + } + // Build and send + gMessageSystem->newMessage( message.c_str() ); + for(parts_iter = parts.begin(); parts_iter != parts_end; ++parts_iter) + { + const char* block_name = (*parts_iter).name.c_str(); + gMessageSystem->nextBlock(block_name); + std::vector<parts_var>::iterator part_var_end = (*parts_iter).vars.end(); + for(std::vector<parts_var>::iterator part_var_iter = (*parts_iter).vars.begin(); + part_var_iter != part_var_end; ++part_var_iter) + { + parts_var pv = (*part_var_iter); + if(!addField(pv.var_type, pv.name.c_str(), pv.value, pv.hex)) + { + LLFloaterChat::addChat(LLChat(llformat("Error adding the provided data for %s '%s' to '%s' block", mvtstr(pv.var_type).c_str(), pv.name.c_str(), block_name))); + gMessageSystem->clearMessage(); + return; + } + } + } + + LLScrollListCtrl* scrollp = floaterp->getChild<LLScrollListCtrl>("net_list"); + LLScrollListItem* selected_itemp = scrollp->getFirstSelected(); + + //if a specific circuit is selected, send it to that, otherwise send it to the current sim + if(selected_itemp) + { + LLNetListItem* itemp = findNetListItem(selected_itemp->getUUID()); + LLScrollListText* textColumn = (LLScrollListText*)selected_itemp->getColumn(1); + + //why would you send data through a dead circuit? + if(textColumn->getValue().asString() == "Dead") + { + LLFloaterChat::addChat(LLChat("No sending messages through dead circuits!")); + return; + } + if(outgoing) + { + gMessageSystem->sendMessage(itemp->mCircuitData->getHost()); + } else { + U8 builtMessageBuffer[MAX_BUFFER_SIZE]; + + S32 message_size = gMessageSystem->mTemplateMessageBuilder->buildMessage(builtMessageBuffer, MAX_BUFFER_SIZE, 0); + gMessageSystem->clearMessage(); + gMessageSystem->checkMessages(0, true, builtMessageBuffer, itemp->mCircuitData->getHost(), message_size); + + } + } else { + if(outgoing) + { + gMessageSystem->sendMessage(gAgent.getRegionHost()); + } else { + U8 builtMessageBuffer[MAX_BUFFER_SIZE]; + + S32 message_size = gMessageSystem->mTemplateMessageBuilder->buildMessage(builtMessageBuffer, MAX_BUFFER_SIZE, 0); + gMessageSystem->clearMessage(); + gMessageSystem->checkMessages(0, true, builtMessageBuffer, gAgent.getRegionHost(), message_size); + + } + } +} + +BOOL LLFloaterMessageBuilder::handleKeyHere(KEY key, MASK mask) +{ + if(key == KEY_RETURN && (mask & MASK_CONTROL)) + { + onClickSend(this); + return TRUE; + } + if(key == KEY_ESCAPE) + { + releaseFocus(); + return TRUE; + } + return FALSE; +} +// </edit> diff --git a/linden/indra/newview/llfloatermessagebuilder.h b/linden/indra/newview/llfloatermessagebuilder.h new file mode 100644 index 000000000..5dc9b4297 --- /dev/null +++ b/linden/indra/newview/llfloatermessagebuilder.h @@ -0,0 +1,55 @@ +// <edit>] +#ifndef LL_LLFLOATERMESSAGEBUILDER_H +#define LL_LLFLOATERMESSAGEBUILDER_H +#include "llfloater.h" +#include "lltemplatemessagereader.h" +#include "llmessagelog.h" + +class LLNetListItem +{ +public: + LLNetListItem(LLUUID id); + LLUUID mID; + BOOL mAutoName; + std::string mName; + std::string mPreviousRegionName; + LLCircuitData* mCircuitData; +}; + +class LLFloaterMessageBuilder : public LLFloater, public LLEventTimer +{ +public: + LLFloaterMessageBuilder(std::string initial_text); + ~LLFloaterMessageBuilder(); + static void show(std::string initial_text); + static std::list<LLNetListItem*> sNetListItems; + BOOL postBuild(); + BOOL tick(); + static BOOL addField(e_message_variable_type var_type, const char* var_name, std::string input, BOOL hex); + static void onClickSend(void* user_data); + static void onCommitPacketCombo(LLUICtrl* ctrl, void* user_data); + static LLFloaterMessageBuilder* sInstance; + BOOL handleKeyHere(KEY key, MASK mask); + std::string mInitialText; + struct parts_var + { + std::string name; + std::string value; + BOOL hex; + e_message_variable_type var_type; + }; + struct parts_block + { + std::string name; + std::vector<parts_var> vars; + }; + static LLNetListItem* findNetListItem(LLHost host); + static LLNetListItem* findNetListItem(LLUUID id); + void refreshNetList(); + enum ENetInfoMode { NI_NET, NI_LOG }; + ENetInfoMode mNetInfoMode; + static void onCommitMessageLog(LLUICtrl* ctrl, void* user_data); + static void onCommitFilter(LLUICtrl* ctrl, void* user_data); +}; +#endif +// </edit> diff --git a/linden/indra/newview/llfloatermessagelog.cpp b/linden/indra/newview/llfloatermessagelog.cpp new file mode 100644 index 000000000..161779b35 --- /dev/null +++ b/linden/indra/newview/llfloatermessagelog.cpp @@ -0,0 +1,962 @@ +// <edit> +#include "llviewerprecompiledheaders.h" +#include "llfloatermessagelog.h" +#include "lluictrlfactory.h" +#include "llworld.h" +#include "llviewerregion.h" +#include "llscrolllistctrl.h" +#include "lltexteditor.h" +#include "llviewerwindow.h" // alertXml +#include "llmessagetemplate.h" +#include <boost/tokenizer.hpp> +#include "llmenugl.h" +#include "llfloatermessagebuilder.h" +#include "llagent.h" +//////////////////////////////// +// LLFloaterMessageLogItem +//////////////////////////////// +#define MAX_PACKET_LEN (0x2000) +LLTemplateMessageReader* LLFloaterMessageLogItem::sTemplateMessageReader = NULL; +LLFloaterMessageLogItem::LLFloaterMessageLogItem(LLMessageLogEntry entry) +: LLMessageLogEntry(entry.mType, entry.mFromHost, entry.mToHost, entry.mData, entry.mDataSize) +{ + if(!sTemplateMessageReader) + { + sTemplateMessageReader = new LLTemplateMessageReader(gMessageSystem->mMessageNumbers); + } + mID.generate(); + mSequenceID = 0; + if(mType == TEMPLATE) + { + BOOL decode_invalid = FALSE; + S32 decode_len = mDataSize; + std::vector<U8> DecodeBuffer(MAX_PACKET_LEN,0); + memcpy(&(DecodeBuffer[0]),&(mData[0]),decode_len); + U8* decodep = &(DecodeBuffer[0]); + mFlags = DecodeBuffer[0]; + gMessageSystem->zeroCodeExpand(&decodep, &decode_len); + if(decode_len < 7) + decode_invalid = TRUE; + else + { + mSequenceID = ntohl(*((U32*)(&decodep[1]))); + sTemplateMessageReader->clearMessage(); + if(!sTemplateMessageReader->validateMessage(decodep, decode_len, mFromHost, TRUE)) + decode_invalid = TRUE; + else + { + if(!sTemplateMessageReader->decodeData(decodep, mFromHost, TRUE)) + decode_invalid = TRUE; + else + { + LLMessageTemplate* temp = sTemplateMessageReader->getTemplate(); + mName = temp->mName; + mSummary = ""; + + if(mFlags) + { + mSummary.append(" [ "); + if(mFlags & LL_ZERO_CODE_FLAG) + mSummary.append(" Zer "); + if(mFlags & LL_RELIABLE_FLAG) + mSummary.append(" Rel "); + if(mFlags & LL_RESENT_FLAG) + mSummary.append(" Rsd "); + if(mFlags & LL_ACK_FLAG) + mSummary.append(" Ack "); + mSummary.append(" ] "); + } + + LLMessageTemplate::message_block_map_t::iterator blocks_end = temp->mMemberBlocks.end(); + for (LLMessageTemplate::message_block_map_t::iterator blocks_iter = temp->mMemberBlocks.begin(); + blocks_iter != blocks_end; ++blocks_iter) + { + LLMessageBlock* block = (*blocks_iter); + const char* block_name = block->mName; + S32 num_blocks = sTemplateMessageReader->getNumberOfBlocks(block_name); + if(!num_blocks) + mSummary.append(" { } "); + else if(num_blocks > 1) + mSummary.append(llformat(" %s [ %d ] { ... } ", block_name, num_blocks)); + else for(S32 i = 0; i < 1; i++) + { + mSummary.append(" { "); + LLMessageBlock::message_variable_map_t::iterator var_end = block->mMemberVariables.end(); + for (LLMessageBlock::message_variable_map_t::iterator var_iter = block->mMemberVariables.begin(); + var_iter != var_end; ++var_iter) + { + LLMessageVariable* variable = (*var_iter); + const char* var_name = variable->getName(); + BOOL returned_hex; + std::string value = getString(sTemplateMessageReader, block_name, i, var_name, variable->getType(), returned_hex, TRUE); + mSummary.append(llformat(" %s=%s ", var_name, value.c_str())); + } + mSummary.append(" } "); + if(mSummary.length() > 255) break; + } + if(mSummary.length() > 255) + { + mSummary.append(" ... "); + break; + } + } // blocks_iter + } // decode_valid + } + } + if(decode_invalid) + { + mName = "Invalid"; + mSummary = ""; + for(S32 i = 0; i < mDataSize; i++) + mSummary.append(llformat("%02X ", mData[i])); + } + } + else // not template + { + mName = "SOMETHING ELSE"; + mSummary = "TODO: SOMETHING ELSE"; + } +} +LLFloaterMessageLogItem::~LLFloaterMessageLogItem() +{ +} +BOOL LLFloaterMessageLogItem::isOutgoing() +{ + return mFromHost == LLHost(16777343, gMessageSystem->getListenPort()); +} +std::string LLFloaterMessageLogItem::getFull(BOOL show_header) +{ + std::string full(""); + if(mType == TEMPLATE) + { + BOOL decode_invalid = FALSE; + S32 decode_len = mDataSize; + std::vector<U8> DecodeBuffer(MAX_PACKET_LEN,0); + memcpy(&(DecodeBuffer[0]),&(mData[0]),decode_len); + U8* decodep = &(DecodeBuffer[0]); + gMessageSystem->zeroCodeExpand(&decodep, &decode_len); + if(decode_len < 7) + decode_invalid = TRUE; + else + { + sTemplateMessageReader->clearMessage(); + if(!sTemplateMessageReader->validateMessage(decodep, decode_len, mFromHost, TRUE)) + decode_invalid = TRUE; + else + { + if(!sTemplateMessageReader->decodeData(decodep, mFromHost, TRUE)) + decode_invalid = TRUE; + else + { + LLMessageTemplate* temp = sTemplateMessageReader->getTemplate(); + full.append(isOutgoing() ? "out " : "in "); + full.append(llformat("%s\n", temp->mName)); + if(show_header) + { + full.append("[Header]\n"); + full.append(llformat("SequenceID = %u\n", mSequenceID)); + full.append(llformat("LL_ZERO_CODE_FLAG = %s\n", (mFlags & LL_ZERO_CODE_FLAG) ? "True" : "False")); + full.append(llformat("LL_RELIABLE_FLAG = %s\n", (mFlags & LL_RELIABLE_FLAG) ? "True" : "False")); + full.append(llformat("LL_RESENT_FLAG = %s\n", (mFlags & LL_RESENT_FLAG) ? "True" : "False")); + full.append(llformat("LL_ACK_FLAG = %s\n", (mFlags & LL_ACK_FLAG) ? "True" : "False")); + } + LLMessageTemplate::message_block_map_t::iterator blocks_end = temp->mMemberBlocks.end(); + for (LLMessageTemplate::message_block_map_t::iterator blocks_iter = temp->mMemberBlocks.begin(); + blocks_iter != blocks_end; ++blocks_iter) + { + LLMessageBlock* block = (*blocks_iter); + const char* block_name = block->mName; + S32 num_blocks = sTemplateMessageReader->getNumberOfBlocks(block_name); + for(S32 i = 0; i < num_blocks; i++) + { + full.append(llformat("[%s]\n", block->mName)); + LLMessageBlock::message_variable_map_t::iterator var_end = block->mMemberVariables.end(); + for (LLMessageBlock::message_variable_map_t::iterator var_iter = block->mMemberVariables.begin(); + var_iter != var_end; ++var_iter) + { + LLMessageVariable* variable = (*var_iter); + const char* var_name = variable->getName(); + BOOL returned_hex; + std::string value = getString(sTemplateMessageReader, block_name, i, var_name, variable->getType(), returned_hex); + if(returned_hex) + full.append(llformat("%s =| ", var_name)); + else + full.append(llformat("%s = ", var_name)); + // llformat has a 1024 char limit!? + full.append(value); + full.append("\n"); + } + } + } // blocks_iter + } // decode_valid + } + } + if(decode_invalid) + { + full = isOutgoing() ? "out" : "in"; + full.append("\n"); + for(S32 i = 0; i < mDataSize; i++) + full.append(llformat("%02X ", mData[i])); + } + } + else // not template + { + full = "FIXME"; + } + return full; +} +// static +std::string LLFloaterMessageLogItem::getString(LLTemplateMessageReader* readerp, const char* block_name, S32 block_num, const char* var_name, e_message_variable_type var_type, BOOL &returned_hex, BOOL summary_mode) +{ + returned_hex = FALSE; + std::stringstream stream; + char* value; + U32 valueU32; + U16 valueU16; + LLVector3 valueVector3; + LLVector3d valueVector3d; + LLVector4 valueVector4; + LLQuaternion valueQuaternion; + LLUUID valueLLUUID; + switch(var_type) + { + case MVT_U8: + U8 valueU8; + readerp->getU8(block_name, var_name, valueU8, block_num); + stream << U32(valueU8); + break; + case MVT_U16: + readerp->getU16(block_name, var_name, valueU16, block_num); + stream << valueU16; + break; + case MVT_U32: + readerp->getU32(block_name, var_name, valueU32, block_num); + stream << valueU32; + break; + case MVT_U64: + U64 valueU64; + readerp->getU64(block_name, var_name, valueU64, block_num); + stream << valueU64; + break; + case MVT_S8: + S8 valueS8; + readerp->getS8(block_name, var_name, valueS8, block_num); + stream << S32(valueS8); + break; + case MVT_S16: + S16 valueS16; + readerp->getS16(block_name, var_name, valueS16, block_num); + stream << valueS16; + break; + case MVT_S32: + S32 valueS32; + readerp->getS32(block_name, var_name, valueS32, block_num); + stream << valueS32; + break; + /*case MVT_S64: + S64 valueS64; + readerp->getS64(block_name, var_name, valueS64, block_num); + stream << valueS64; + break;*/ + case MVT_F32: + F32 valueF32; + readerp->getF32(block_name, var_name, valueF32, block_num); + stream << valueF32; + break; + case MVT_F64: + F64 valueF64; + readerp->getF64(block_name, var_name, valueF64, block_num); + stream << valueF64; + break; + case MVT_LLVector3: + readerp->getVector3(block_name, var_name, valueVector3, block_num); + //stream << valueVector3; + stream << "<" << valueVector3.mV[0] << ", " << valueVector3.mV[1] << ", " << valueVector3.mV[2] << ">"; + break; + case MVT_LLVector3d: + readerp->getVector3d(block_name, var_name, valueVector3d, block_num); + //stream << valueVector3d; + stream << "<" << valueVector3d.mdV[0] << ", " << valueVector3d.mdV[1] << ", " << valueVector3d.mdV[2] << ">"; + break; + case MVT_LLVector4: + readerp->getVector4(block_name, var_name, valueVector4, block_num); + //stream << valueVector4; + stream << "<" << valueVector4.mV[0] << ", " << valueVector4.mV[1] << ", " << valueVector4.mV[2] << ", " << valueVector4.mV[3] << ">"; + break; + case MVT_LLQuaternion: + readerp->getQuat(block_name, var_name, valueQuaternion, block_num); + //stream << valueQuaternion; + stream << "<" << valueQuaternion.mQ[0] << ", " << valueQuaternion.mQ[1] << ", " << valueQuaternion.mQ[2] << ", " << valueQuaternion.mQ[3] << ">"; + break; + case MVT_LLUUID: + readerp->getUUID(block_name, var_name, valueLLUUID, block_num); + stream << valueLLUUID; + break; + case MVT_BOOL: + BOOL valueBOOL; + readerp->getBOOL(block_name, var_name, valueBOOL, block_num); + stream << valueBOOL; + break; + case MVT_IP_ADDR: + readerp->getIPAddr(block_name, var_name, valueU32, block_num); + stream << LLHost(valueU32, 0).getIPString(); + break; + case MVT_IP_PORT: + readerp->getIPPort(block_name, var_name, valueU16, block_num); + stream << valueU16; + case MVT_VARIABLE: + case MVT_FIXED: + default: + S32 size = readerp->getSize(block_name, block_num, var_name); + if(size) + { + value = new char[size + 1]; + readerp->getBinaryData(block_name, var_name, value, size, block_num); + value[size] = '\0'; + S32 readable = 0; + S32 unreadable = 0; + S32 end = (summary_mode && (size > 64)) ? 64 : size; + for(S32 i = 0; i < end; i++) + { + if(!value[i]) + { + if(i != (end - 1)) + { // don't want null terminator hiding data + unreadable = S32_MAX; + break; + } + } + else if(value[i] < 0x20 || value[i] >= 0x7F) + { + if(summary_mode) + unreadable++; + else + { // never want any wrong characters outside of summary mode + unreadable = S32_MAX; + break; + } + } + else readable++; + } + if(readable >= unreadable) + { + if(summary_mode && (size > 64)) + { + for(S32 i = 60; i < 63; i++) + value[i] = '.'; + value[63] = '\0'; + } + stream << value; + + delete[] value; + } + else + { + returned_hex = TRUE; + S32 end = (summary_mode && (size > 8)) ? 8 : size; + for(S32 i = 0; i < end; i++) + //stream << std::uppercase << std::hex << U32(value[i]) << " "; + stream << llformat("%02X ", (U8)value[i]); + if(summary_mode && (size > 8)) + stream << " ... "; + } + } + break; + } + + return stream.str(); +} +LLMessageLogFilter::LLMessageLogFilter() +{ +} +LLMessageLogFilter::~LLMessageLogFilter() +{ +} +BOOL LLMessageLogFilter::set(std::string filter) +{ + mPositiveNames.clear(); + mNegativeNames.clear(); + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep(" ","",boost::keep_empty_tokens); + boost::tokenizer<boost::char_separator<char> > tokens(filter, sep); + boost::tokenizer<boost::char_separator<char> >::iterator end = tokens.end(); + for(boost::tokenizer<boost::char_separator<char> >::iterator iter = tokens.begin(); iter != end; ++iter) + { + std::string token = (*iter); + LLStringUtil::trim(token); + LLStringUtil::toLower(token); + BOOL negative = token.find("!") == 0; + if(negative) + { + token = token.substr(1); + mNegativeNames.push_back(token); + } + else + mPositiveNames.push_back(token); + } + return TRUE; +} +//////////////////////////////// +// LLMessageLogFilterApply +//////////////////////////////// +LLMessageLogFilterApply::LLMessageLogFilterApply() +: LLEventTimer(0.1f), + mFinished(FALSE), + mProgress(0) +{ + mIter = LLFloaterMessageLog::sMessageLogEntries.begin(); +} +void LLMessageLogFilterApply::cancel() +{ + mFinished = TRUE; +} +BOOL LLMessageLogFilterApply::tick() +{ + std::deque<LLMessageLogEntry>::iterator end = LLFloaterMessageLog::sMessageLogEntries.end(); + if(mIter == end || !LLFloaterMessageLog::sInstance) + { + mFinished = TRUE; + if(LLFloaterMessageLog::sInstance) + { + if(LLFloaterMessageLog::sInstance->mMessageLogFilterApply == this) + { + LLFloaterMessageLog::sInstance->stopApplyingFilter(); + } + } + return TRUE; + } + for(S32 i = 0; i < 256; i++) + { + if(mIter == end) + { + mFinished = TRUE; + if(LLFloaterMessageLog::sInstance) + { + if(LLFloaterMessageLog::sInstance->mMessageLogFilterApply == this) + { + LLFloaterMessageLog::sInstance->stopApplyingFilter(); + + //we're done messing with the deque, push all queued items to the main deque + std::deque<LLMessageLogEntry>::iterator queueIter = mQueuedMessages.begin(); + std::deque<LLMessageLogEntry>::iterator queueEnd = mQueuedMessages.end(); + + while(queueIter != queueEnd) + { + LLFloaterMessageLog::sInstance->conditionalLog(LLFloaterMessageLogItem((*queueIter))); + ++queueIter; + } + + mQueuedMessages.clear(); + } + } + + return TRUE; + } + + LLFloaterMessageLog::sInstance->conditionalLog(LLFloaterMessageLogItem((*mIter))); + + mIter++; + mProgress++; + } + LLFloaterMessageLog::sInstance->updateFilterStatus(); + return FALSE; +} +//////////////////////////////// +// LLFloaterMessageLog +//////////////////////////////// +LLFloaterMessageLog* LLFloaterMessageLog::sInstance; +std::list<LLNetListItem*> LLFloaterMessageLog::sNetListItems; +std::deque<LLMessageLogEntry> LLFloaterMessageLog::sMessageLogEntries; +std::vector<LLFloaterMessageLogItem> LLFloaterMessageLog::sFloaterMessageLogItems; +LLMessageLogFilter LLFloaterMessageLog::sMessageLogFilter = LLMessageLogFilter(); +std::string LLFloaterMessageLog::sMessageLogFilterString("!StartPingCheck !CompletePingCheck !PacketAck !SimulatorViewerTimeMessage !SimStats !AgentUpdate !AgentAnimation !AvatarAnimation !ViewerEffect !CoarseLocationUpdate !LayerData !CameraConstraint !ObjectUpdateCached !RequestMultipleObjects !ObjectUpdate !ObjectUpdateCompressed !ImprovedTerseObjectUpdate !KillObject !ImagePacket !SendXferPacket !ConfirmXferPacket !TransferPacket !SoundTrigger !AttachedSound !PreloadSound"); +BOOL LLFloaterMessageLog::sBusyApplyingFilter = FALSE; +LLFloaterMessageLog::LLFloaterMessageLog() +: LLFloater(), + LLEventTimer(1.0f), + mNetInfoMode(NI_NET), + mMessageLogFilterApply(NULL) +{ + sInstance = this; + LLMessageLog::setCallback(onLog); + sMessageLogEntries = LLMessageLog::getDeque(); + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_message_log.xml"); +} +LLFloaterMessageLog::~LLFloaterMessageLog() +{ + LLMessageLog::setCallback(NULL); + stopApplyingFilter(); + sInstance = NULL; + sNetListItems.clear(); + sMessageLogEntries.clear(); + sFloaterMessageLogItems.clear(); +} +// static +void LLFloaterMessageLog::show() +{ + if(!sInstance) sInstance = new LLFloaterMessageLog(); + sInstance->open(); +} +BOOL LLFloaterMessageLog::postBuild() +{ + childSetCommitCallback("net_list", onCommitNetList, this); + childSetCommitCallback("message_log", onCommitMessageLog, this); + childSetAction("filter_choice_btn", onClickFilterChoice, this); + childSetAction("filter_apply_btn", onClickFilterApply, this); + childSetCommitCallback("filter_edit", onCommitFilter, this); + childSetAction("clear_log_btn", onClickClearLog, this); + childSetAction("send_to_message_builder_btn", onClickSendToMessageBuilder, this); + childSetText("filter_edit", sMessageLogFilterString); + refreshNetList(); + refreshNetInfo(TRUE); + startApplyingFilter(sMessageLogFilterString, TRUE); + return TRUE; +} +BOOL LLFloaterMessageLog::tick() +{ + refreshNetList(); + refreshNetInfo(FALSE); + return FALSE; +} +LLNetListItem* LLFloaterMessageLog::findNetListItem(LLHost host) +{ + std::list<LLNetListItem*>::iterator end = sNetListItems.end(); + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != end; ++iter) + if((*iter)->mCircuitData && (*iter)->mCircuitData->getHost() == host) + return (*iter); + return NULL; +} +LLNetListItem* LLFloaterMessageLog::findNetListItem(LLUUID id) +{ + std::list<LLNetListItem*>::iterator end = sNetListItems.end(); + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != end; ++iter) + if((*iter)->mID == id) + return (*iter); + return NULL; +} +void LLFloaterMessageLog::refreshNetList() +{ + LLScrollListCtrl* scrollp = getChild<LLScrollListCtrl>("net_list"); + // Update circuit data of net list items + std::vector<LLCircuitData*> circuits = gMessageSystem->getCircuit()->getCircuitDataList(); + std::vector<LLCircuitData*>::iterator circuits_end = circuits.end(); + for(std::vector<LLCircuitData*>::iterator iter = circuits.begin(); iter != circuits_end; ++iter) + { + LLNetListItem* itemp = findNetListItem((*iter)->getHost()); + if(!itemp) + { + LLUUID id; id.generate(); + itemp = new LLNetListItem(id); + sNetListItems.push_back(itemp); + } + itemp->mCircuitData = (*iter); + } + // Clear circuit data of items whose circuits are gone + std::list<LLNetListItem*>::iterator items_end = sNetListItems.end(); + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != items_end; ++iter) + { + if(std::find(circuits.begin(), circuits.end(), (*iter)->mCircuitData) == circuits.end()) + (*iter)->mCircuitData = NULL; + } + // Remove net list items that are totally useless now + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != sNetListItems.end();) + { + if((*iter)->mCircuitData == NULL) + iter = sNetListItems.erase(iter); + else ++iter; + } + // Update names of net list items + items_end = sNetListItems.end(); + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != items_end; ++iter) + { + LLNetListItem* itemp = (*iter); + if(itemp->mAutoName) + { + if(itemp->mCircuitData) + { + LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(itemp->mCircuitData->getHost()); + if(regionp) + { + std::string name = regionp->getName(); + if(name == "") name = llformat("%s (awaiting region name)", itemp->mCircuitData->getHost().getString().c_str()); + itemp->mName = name; + itemp->mPreviousRegionName = name; + } + else + { + itemp->mName = itemp->mCircuitData->getHost().getString(); + if(itemp->mPreviousRegionName != "") + itemp->mName.append(llformat(" (was %s)", itemp->mPreviousRegionName.c_str())); + } + } + else + { + // an item just for an event queue, not handled yet + itemp->mName = "Something else"; + } + } + } + // Rebuild scroll list from scratch + LLUUID selected_id = scrollp->getFirstSelected() ? scrollp->getFirstSelected()->getUUID() : LLUUID::null; + S32 scroll_pos = scrollp->getScrollPos(); + scrollp->clearRows(); + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != items_end; ++iter) + { + LLNetListItem* itemp = (*iter); + LLSD element; + element["id"] = itemp->mID; + LLSD& text_column = element["columns"][0]; + text_column["column"] = "text"; + text_column["value"] = itemp->mName + (itemp->mCircuitData->getHost() == gAgent.getRegionHost() ? " (main)" : ""); + for(int i = 0; i < 2; i++) + { + LLSD& icon_column = element["columns"][i + 1]; + icon_column["column"] = llformat("icon%d", i); + icon_column["type"] = "icon"; + icon_column["value"] = ""; + } + LLScrollListItem* scroll_itemp = scrollp->addElement(element); + BOOL has_live_circuit = itemp->mCircuitData && itemp->mCircuitData->isAlive(); + if(has_live_circuit) + { + LLScrollListIcon* icon = (LLScrollListIcon*)scroll_itemp->getColumn(1); + icon->setValue("icon_net_close_circuit.tga"); + icon->setClickCallback(onClickCloseCircuit, itemp); + } + else + { + LLScrollListIcon* icon = (LLScrollListIcon*)scroll_itemp->getColumn(1); + icon->setValue("icon_net_close_circuit_gray.tga"); + icon->setClickCallback(NULL, NULL); + } + // Event queue isn't even supported yet... FIXME + LLScrollListIcon* icon = (LLScrollListIcon*)scroll_itemp->getColumn(2); + icon->setValue("icon_net_close_eventpoll_gray.tga"); + icon->setClickCallback(NULL, NULL); + } + if(selected_id.notNull()) scrollp->selectByID(selected_id); + if(scroll_pos < scrollp->getItemCount()) scrollp->setScrollPos(scroll_pos); +} +void LLFloaterMessageLog::refreshNetInfo(BOOL force) +{ + if(mNetInfoMode != NI_NET) return; + LLScrollListCtrl* scrollp = getChild<LLScrollListCtrl>("net_list"); + LLScrollListItem* selected_itemp = scrollp->getFirstSelected(); + if(selected_itemp) + { + if(!force) if(getChild<LLTextEditor>("net_info")->hasSelection()) return; + LLNetListItem* itemp = findNetListItem(selected_itemp->getUUID()); + if(itemp) + { + std::string info(llformat("%s\n--------------------------------\n\n", itemp->mName.c_str())); + if(itemp->mCircuitData) + { + LLCircuitData* cdp = itemp->mCircuitData; + info.append("Circuit\n--------------------------------\n"); + info.append(llformat(" * Host: %s\n", cdp->getHost().getString().c_str())); + S32 seconds = (S32)cdp->getAgeInSeconds(); + S32 minutes = seconds / 60; + seconds = seconds % 60; + S32 hours = minutes / 60; + minutes = minutes % 60; + info.append(llformat(" * Age: %dh %dm %ds\n", hours, minutes, seconds)); + info.append(llformat(" * Alive: %s\n", cdp->isAlive() ? "yes" : "no")); + info.append(llformat(" * Blocked: %s\n", cdp->isBlocked() ? "yes" : "no")); + info.append(llformat(" * Allow timeout: %s\n", cdp->getAllowTimeout() ? "yes" : "no")); + info.append(llformat(" * Trusted: %s\n", cdp->getTrusted() ? "yes" : "no")); + info.append(llformat(" * Ping delay: %d\n", cdp->getPingDelay())); + info.append(llformat(" * Packets out: %d\n", cdp->getPacketsOut())); + info.append(llformat(" * Bytes out: %d\n", cdp->getBytesOut())); + info.append(llformat(" * Packets in: %d\n", cdp->getPacketsIn())); + info.append(llformat(" * Bytes in: %d\n", cdp->getBytesIn())); + info.append(llformat(" * Endpoint ID: %s\n", cdp->getLocalEndPointID().asString().c_str())); + info.append(llformat(" * Remote ID: %s\n", cdp->getRemoteID().asString().c_str())); + info.append(llformat(" * Remote session ID: %s\n", cdp->getRemoteSessionID().asString().c_str())); + } + childSetText("net_info", info); + } + else childSetText("net_info", std::string("")); + } + else childSetText("net_info", std::string("")); +} +void LLFloaterMessageLog::setNetInfoMode(ENetInfoMode mode) +{ + mNetInfoMode = mode; + if(mNetInfoMode == NI_NET) + refreshNetInfo(TRUE); + childSetEnabled("send_to_message_builder_btn", mNetInfoMode == NI_LOG); +} +// static +void LLFloaterMessageLog::onLog(LLMessageLogEntry entry) +{ + //don't mess with the queue while a filter's being applied, or face invalid iterators + if(!sBusyApplyingFilter) + { + sMessageLogEntries.push_back(entry); + conditionalLog(LLFloaterMessageLogItem(entry)); + } +} +// static +void LLFloaterMessageLog::conditionalLog(LLFloaterMessageLogItem item) +{ + if(!sBusyApplyingFilter) + sInstance->childSetText("log_status_text", llformat("Showing %d messages from %d", sFloaterMessageLogItems.size(), sMessageLogEntries.size())); + std::string find_name = item.mName; + LLStringUtil::toLower(find_name); + if(sMessageLogFilter.mPositiveNames.size()) + if(std::find(sMessageLogFilter.mPositiveNames.begin(), sMessageLogFilter.mPositiveNames.end(), find_name) == sMessageLogFilter.mPositiveNames.end()) + return; + if(std::find(sMessageLogFilter.mNegativeNames.begin(), sMessageLogFilter.mNegativeNames.end(), find_name) != sMessageLogFilter.mNegativeNames.end()) + return; + sFloaterMessageLogItems.push_back(item); // moved from beginning... + BOOL outgoing = item.isOutgoing(); + std::string net_name("\?\?\?"); + if(item.mType == LLFloaterMessageLogItem::TEMPLATE) + { + LLHost find_host = outgoing ? item.mToHost : item.mFromHost; + net_name = find_host.getIPandPort(); + std::list<LLNetListItem*>::iterator end = sNetListItems.end(); + for(std::list<LLNetListItem*>::iterator iter = sNetListItems.begin(); iter != end; ++iter) + { + if((*iter)->mCircuitData->getHost() == find_host) + { + net_name = (*iter)->mName; + break; + } + } + } + LLSD element; + element["id"] = item.mID; + LLSD& sequence_column = element["columns"][0]; + sequence_column["column"] = "sequence"; + sequence_column["value"] = llformat("%u", item.mSequenceID); + LLSD& type_column = element["columns"][1]; + type_column["column"] = "type"; + type_column["value"] = item.mType == LLFloaterMessageLogItem::TEMPLATE ? "UDP" : "\?\?\?"; + LLSD& direction_column = element["columns"][2]; + direction_column["column"] = "direction"; + direction_column["value"] = outgoing ? "to" : "from"; + LLSD& net_column = element["columns"][3]; + net_column["column"] = "net"; + net_column["value"] = net_name; + LLSD& name_column = element["columns"][4]; + name_column["column"] = "name"; + name_column["value"] = item.mName; + /* + LLSD& zer_column = element["columns"][5]; + zer_column["column"] = "flag_zer"; + zer_column["type"] = "icon"; + zer_column["value"] = (item.mFlags & LL_ZERO_CODE_FLAG) ? "flag_zer.tga" : ""; + LLSD& rel_column = element["columns"][6]; + rel_column["column"] = "flag_rel"; + rel_column["type"] = "icon"; + rel_column["value"] = (item.mFlags & LL_RELIABLE_FLAG) ? "flag_rel.tga" : ""; + LLSD& rsd_column = element["columns"][7]; + rsd_column["column"] = "flag_rsd"; + rsd_column["type"] = "icon"; + rsd_column["value"] = (item.mFlags & LL_RESENT_FLAG) ? "flag_rsd.tga" : ""; + LLSD& ack_column = element["columns"][8]; + ack_column["column"] = "flag_ack"; + ack_column["type"] = "icon"; + ack_column["value"] = (item.mFlags & LL_ACK_FLAG) ? "flag_ack.tga" : ""; + */ + LLSD& summary_column = element["columns"][5]; + summary_column["column"] = "summary"; + summary_column["value"] = item.mSummary; + LLScrollListCtrl* scrollp = sInstance->getChild<LLScrollListCtrl>("message_log"); + S32 scroll_pos = scrollp->getScrollPos(); + scrollp->addElement(element); + if(scroll_pos > scrollp->getItemCount() - scrollp->getPageLines() - 4) + scrollp->setScrollPos(scrollp->getItemCount()); +} +// static +void LLFloaterMessageLog::onCommitNetList(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data; + floaterp->setNetInfoMode(NI_NET); + floaterp->refreshNetInfo(TRUE); +} +// static +void LLFloaterMessageLog::onCommitMessageLog(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data; + LLScrollListCtrl* scrollp = floaterp->getChild<LLScrollListCtrl>("message_log"); + LLScrollListItem* selected_itemp = scrollp->getFirstSelected(); + if(!selected_itemp) return; + LLUUID id = selected_itemp->getUUID(); + std::vector<LLFloaterMessageLogItem>::iterator end = sFloaterMessageLogItems.end(); + for(std::vector<LLFloaterMessageLogItem>::iterator iter = sFloaterMessageLogItems.begin(); iter != end; ++iter) + { + if(iter->mID == id) + { + floaterp->setNetInfoMode(NI_LOG); + floaterp->childSetText("net_info", iter->getFull(FALSE)); + break; + } + } +} +// static +BOOL LLFloaterMessageLog::onClickCloseCircuit(void* user_data) +{ + LLNetListItem* itemp = (LLNetListItem*)user_data; + LLCircuitData* cdp = (LLCircuitData*)itemp->mCircuitData; + if(!cdp) return FALSE; + LLHost myhost = cdp->getHost(); + LLSD args; + args["MESSAGE"] = "This will delete local circuit data.\nDo you want to tell the remote host to close the circuit too?"; + LLSD payload; + payload["circuittoclose"] = myhost.getString(); + LLNotifications::instance().add("GenericAlertYesCancel", args, payload, onConfirmCloseCircuit); + return TRUE; +} +// static +bool LLFloaterMessageLog::onConfirmCloseCircuit(const LLSD& notification, const LLSD& response ) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + LLCircuitData* cdp = gMessageSystem->mCircuitInfo.findCircuit(LLHost(notification["payload"]["circuittoclose"].asString())); + if(!cdp) return false; + LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(cdp->getHost()); + switch(option) + { + case 0: // yes + gMessageSystem->newMessageFast(_PREHASH_CloseCircuit); + gMessageSystem->sendReliable(cdp->getHost()); + break; + case 2: // cancel + return false; + break; + case 1: // no + default: + break; + } + if(gMessageSystem->findCircuitCode(cdp->getHost())) + gMessageSystem->disableCircuit(cdp->getHost()); + else + gMessageSystem->getCircuit()->removeCircuitData(cdp->getHost()); + if(regionp) + { + LLHost myhost = regionp->getHost(); + LLSD args; + args["MESSAGE"] = "That host had a region associated with it.\nDo you want to clean that up?"; + LLSD payload; + payload["regionhost"] = myhost.getString(); + LLNotifications::instance().add("GenericAlertYesCancel", args, payload, onConfirmRemoveRegion); + } + return false; +} +// static +bool LLFloaterMessageLog::onConfirmRemoveRegion(const LLSD& notification, const LLSD& response ) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if(option == 0) // yes + LLWorld::getInstance()->removeRegion(LLHost(notification["payload"]["regionhost"].asString())); + return false; +} +// static +void LLFloaterMessageLog::onClickFilterApply(void* user_data) +{ + LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data; + floaterp->startApplyingFilter(floaterp->childGetValue("filter_edit"), FALSE); +} +void LLFloaterMessageLog::startApplyingFilter(std::string filter, BOOL force) +{ + LLMessageLogFilter new_filter = LLMessageLogFilter(); + sMessageLogFilterString = filter; + new_filter.set(sMessageLogFilterString); + if(!filter.length() || filter.at(filter.length()-1) != ' ') + childSetText("filter_edit", filter + " "); + if(force + || (new_filter.mNegativeNames != sMessageLogFilter.mNegativeNames) + || (new_filter.mPositiveNames != sMessageLogFilter.mPositiveNames)) + { + stopApplyingFilter(); + sMessageLogFilter = new_filter; + sFloaterMessageLogItems.clear(); + getChild<LLScrollListCtrl>("message_log")->clearRows(); + sBusyApplyingFilter = TRUE; + childSetVisible("message_log", false); + //childSetVisible("log_status_text", true); + mMessageLogFilterApply = new LLMessageLogFilterApply(); + } +} +void LLFloaterMessageLog::stopApplyingFilter() +{ + if(mMessageLogFilterApply) + { + if(!(mMessageLogFilterApply->mFinished)) + mMessageLogFilterApply->cancel(); + //delete mMessageLogFilterApply; + sBusyApplyingFilter = FALSE; + //childSetVisible("log_status_text", false); + childSetVisible("message_log", true); + childSetText("log_status_text", llformat("Showing %d messages from %d", sFloaterMessageLogItems.size(), sMessageLogEntries.size())); + } +} +void LLFloaterMessageLog::updateFilterStatus() +{ + if(!mMessageLogFilterApply || !sBusyApplyingFilter) return; + S32 progress = mMessageLogFilterApply->mProgress; + S32 packets = sMessageLogEntries.size(); + S32 matches = sFloaterMessageLogItems.size(); + std::string text = llformat("Applying filter ( %d / %d ), %d matches ...", progress, packets, matches); + childSetText("log_status_text", text); +} +// static +void LLFloaterMessageLog::onCommitFilter(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data; + floaterp->startApplyingFilter(floaterp->childGetValue("filter_edit"), FALSE); +} +// static +void LLFloaterMessageLog::onClickClearLog(void* user_data) +{ + LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data; + floaterp->stopApplyingFilter(); + floaterp->getChild<LLScrollListCtrl>("message_log")->clearRows(); + floaterp->setNetInfoMode(NI_NET); + sMessageLogEntries.clear(); + sFloaterMessageLogItems.clear(); +} +// static +void LLFloaterMessageLog::onClickFilterChoice(void* user_data) +{ + LLMenuGL* menu = new LLMenuGL(LLStringUtil::null); + menu->append(new LLMenuItemCallGL("No filter", onClickFilterMenu, NULL, (void*)"")); + menu->append(new LLMenuItemCallGL("Fewer spammy messages", onClickFilterMenu, NULL, (void*)"!StartPingCheck !CompletePingCheck !PacketAck !SimulatorViewerTimeMessage !SimStats !AgentUpdate !AgentAnimation !AvatarAnimation !ViewerEffect !CoarseLocationUpdate !LayerData !CameraConstraint !ObjectUpdateCached !RequestMultipleObjects !ObjectUpdate !ObjectUpdateCompressed !ImprovedTerseObjectUpdate !KillObject !ImagePacket !SendXferPacket !ConfirmXferPacket !TransferPacket")); + menu->append(new LLMenuItemCallGL("Fewer spammy messages (minus sound crap)", onClickFilterMenu, NULL, (void*)"!StartPingCheck !CompletePingCheck !PacketAck !SimulatorViewerTimeMessage !SimStats !AgentUpdate !AgentAnimation !AvatarAnimation !ViewerEffect !CoarseLocationUpdate !LayerData !CameraConstraint !ObjectUpdateCached !RequestMultipleObjects !ObjectUpdate !ObjectUpdateCompressed !ImprovedTerseObjectUpdate !KillObject !ImagePacket !SendXferPacket !ConfirmXferPacket !TransferPacket !SoundTrigger !AttachedSound !PreloadSound")); + menu->append(new LLMenuItemCallGL("Object updates", onClickFilterMenu, NULL, (void*)"ObjectUpdateCached ObjectUpdate ObjectUpdateCompressed ImprovedTerseObjectUpdate KillObject RequestMultipleObjects")); + menu->append(new LLMenuItemCallGL("Abnormal", onClickFilterMenu, NULL, (void*)"Invalid TestMessage AddCircuitCode NeighborList AvatarTextureUpdate SimulatorMapUpdate SimulatorSetMap SubscribeLoad UnsubscribeLoad SimulatorReady SimulatorPresentAtLocation SimulatorLoad SimulatorShutdownRequest RegionPresenceRequestByRegionID RegionPresenceRequestByHandle RegionPresenceResponse UpdateSimulator LogDwellTime FeatureDisabled LogFailedMoneyTransaction UserReportInternal SetSimStatusInDatabase SetSimPresenceInDatabase OpenCircuit CloseCircuit DirFindQueryBackend DirPlacesQueryBackend DirClassifiedQueryBackend DirLandQueryBackend DirPopularQueryBackend GroupNoticeAdd DataHomeLocationRequest DataHomeLocationReply DerezContainer ObjectCategory ObjectExportSelected StateSave ReportAutosaveCrash AgentAlertMessage NearestLandingRegionRequest NearestLandingRegionReply NearestLandingRegionUpdated TeleportLandingStatusChanged ConfirmEnableSimulator KickUserAck SystemKickUser AvatarPropertiesRequestBackend UpdateParcel RemoveParcel MergeParcel LogParcelChanges CheckParcelSales ParcelSales StartAuction ConfirmAuctionStart CompleteAuction CancelAuction CheckParcelAuctions ParcelAuctions ChatPass EdgeDataPacket SimStatus ChildAgentUpdate ChildAgentAlive ChildAgentPositionUpdate ChildAgentDying ChildAgentUnknown AtomicPassObject KillChildAgents ScriptSensorRequest ScriptSensorReply DataServerLogout RequestInventoryAsset InventoryAssetResponse TransferInventory TransferInventoryAck EventLocationRequest EventLocationReply MoneyTransferBackend RoutedMoneyBalanceReply SetStartLocation NetTest SetCPURatio SimCrashed NameValuePair RemoveNameValuePair UpdateAttachment RemoveAttachment EmailMessageRequest EmailMessageReply InternalScriptMail ScriptDataRequest ScriptDataReply InviteGroupResponse TallyVotes LiveHelpGroupRequest LiveHelpGroupReply GroupDataUpdate LogTextMessage CreateTrustedCircuit ParcelRename SystemMessage RpcChannelRequest RpcChannelReply RpcScriptRequestInbound RpcScriptRequestInboundForward RpcScriptReplyInbound ScriptMailRegistration Error")); + menu->updateParent(LLMenuGL::sMenuContainer); + menu->setCanTearOff(FALSE); + LLView* buttonp = sInstance->getChild<LLView>("filter_choice_btn"); + S32 x = buttonp->getRect().mLeft; + S32 y = buttonp->getRect().mBottom; + LLMenuGL::showPopup(sInstance, menu, x, y); +} +// static +void LLFloaterMessageLog::onClickFilterMenu(void* user_data) +{ + std::string filter = std::string((char*)user_data); + sInstance->childSetText("filter_edit", filter); + sInstance->startApplyingFilter(filter, FALSE); +} +// static +void LLFloaterMessageLog::onClickSendToMessageBuilder(void* user_data) +{ + LLFloaterMessageLog* floaterp = (LLFloaterMessageLog*)user_data; + LLScrollListCtrl* scrollp = floaterp->getChild<LLScrollListCtrl>("message_log"); + LLScrollListItem* selected_itemp = scrollp->getFirstSelected(); + if(!selected_itemp) return; + LLUUID id = selected_itemp->getUUID(); + std::vector<LLFloaterMessageLogItem>::iterator end = sFloaterMessageLogItems.end(); + for(std::vector<LLFloaterMessageLogItem>::iterator iter = sFloaterMessageLogItems.begin(); iter != end; ++iter) + { + if(iter->mID == id) + { + std::string message_text = iter->getFull(FALSE); + LLFloaterMessageBuilder::show(message_text); + break; + } + } +} +// </edit> diff --git a/linden/indra/newview/llfloatermessagelog.h b/linden/indra/newview/llfloatermessagelog.h new file mode 100644 index 000000000..ebc4f2aa6 --- /dev/null +++ b/linden/indra/newview/llfloatermessagelog.h @@ -0,0 +1,84 @@ +// <edit> +#include "llfloater.h" +#include "llmessagelog.h" +#include "lltemplatemessagereader.h" +#include "llfloatermessagebuilder.h" + +class LLFloaterMessageLogItem : public LLMessageLogEntry +{ +public: + LLFloaterMessageLogItem(LLMessageLogEntry entry); + ~LLFloaterMessageLogItem(); + LLUUID mID; + U32 mSequenceID; + std::string mName; + std::string mSummary; + U32 mFlags; + std::string getFull(BOOL show_header = TRUE); + BOOL isOutgoing(); +private: + static LLTemplateMessageReader* sTemplateMessageReader; + static std::string getString(LLTemplateMessageReader* readerp, const char* block_name, S32 block_num, const char* var_name, e_message_variable_type var_type, BOOL &returned_hex, BOOL summary_mode = FALSE); +}; +class LLMessageLogFilter +{ +public: + LLMessageLogFilter(); + ~LLMessageLogFilter(); + BOOL set(std::string filter); + std::list<std::string> mPositiveNames; + std::list<std::string> mNegativeNames; +}; +class LLMessageLogFilterApply : public LLEventTimer +{ +public: + LLMessageLogFilterApply(); + void cancel(); + BOOL tick(); + S32 mProgress; + BOOL mFinished; +private: + std::deque<LLMessageLogEntry> mQueuedMessages; + std::deque<LLMessageLogEntry>::iterator mIter; +}; +class LLFloaterMessageLog : public LLFloater, public LLEventTimer +{ +public: + LLFloaterMessageLog(); + ~LLFloaterMessageLog(); + static void show(); + BOOL postBuild(); + BOOL tick(); + LLNetListItem* findNetListItem(LLHost host); + LLNetListItem* findNetListItem(LLUUID id); + void refreshNetList(); + void refreshNetInfo(BOOL force); + enum ENetInfoMode { NI_NET, NI_LOG }; + void setNetInfoMode(ENetInfoMode mode); + static void onLog(LLMessageLogEntry entry); + static void conditionalLog(LLFloaterMessageLogItem item); + static void onCommitNetList(LLUICtrl* ctrl, void* user_data); + static void onCommitMessageLog(LLUICtrl* ctrl, void* user_data); + static void onCommitFilter(LLUICtrl* ctrl, void* user_data); + static BOOL onClickCloseCircuit(void* user_data); + static bool onConfirmCloseCircuit(const LLSD& notification, const LLSD& response ); + static bool onConfirmRemoveRegion(const LLSD& notification, const LLSD& response ); + static void onClickFilterApply(void* user_data); + void startApplyingFilter(std::string filter, BOOL force); + void stopApplyingFilter(); + void updateFilterStatus(); + static BOOL sBusyApplyingFilter; + LLMessageLogFilterApply* mMessageLogFilterApply; + static void onClickClearLog(void* user_data); + static LLFloaterMessageLog* sInstance; + static std::list<LLNetListItem*> sNetListItems; + static std::deque<LLMessageLogEntry> sMessageLogEntries; + static std::vector<LLFloaterMessageLogItem> sFloaterMessageLogItems; + static LLMessageLogFilter sMessageLogFilter; + static std::string sMessageLogFilterString; + ENetInfoMode mNetInfoMode; + static void onClickFilterChoice(void* user_data); + static void onClickFilterMenu(void* user_data); + static void onClickSendToMessageBuilder(void* user_data); +}; +// </edit> diff --git a/linden/indra/newview/llfloaternamedesc.cpp b/linden/indra/newview/llfloaternamedesc.cpp index 941361189..9e8e94b8a 100644 --- a/linden/indra/newview/llfloaternamedesc.cpp +++ b/linden/indra/newview/llfloaternamedesc.cpp @@ -55,7 +55,7 @@ #include "llassetstorage.h" #include "llinventorytype.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" const S32 PREVIEW_LINE_HEIGHT = 19; const S32 PREVIEW_CLOSE_BOX_SIZE = 16; diff --git a/linden/indra/newview/llfloaterobjectiminfo.cpp b/linden/indra/newview/llfloaterobjectiminfo.cpp index 06e6213b0..19721ccc4 100644 --- a/linden/indra/newview/llfloaterobjectiminfo.cpp +++ b/linden/indra/newview/llfloaterobjectiminfo.cpp @@ -137,7 +137,7 @@ void LLFloaterObjectIMInfo::onClickMap(void* data) std::ostringstream link; link << "secondlife://" << self->mSlurl; - class LLWebBrowserCtrl* web = NULL; + class LLMediaCtrl* web = NULL; LLURLDispatcher::dispatch(link.str(), web, true); } @@ -213,14 +213,14 @@ class LLObjectIMInfoHandler : public LLCommandHandler LLObjectIMInfoHandler() : LLCommandHandler("objectim", true) { } bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web); + LLMediaCtrl* web); }; // Creating the object registers with the dispatcher. LLObjectIMInfoHandler gObjectIMHandler; // ex. secondlife:///app/objectim/9426adfc-9c17-8765-5f09-fdf19957d003?owner=a112d245-9095-4e9c-ace4-ffa31717f934&groupowned=true&slurl=ahern/123/123/123&name=Object -bool LLObjectIMInfoHandler::handle(const LLSD &tokens, const LLSD &query_map, LLWebBrowserCtrl* web) +bool LLObjectIMInfoHandler::handle(const LLSD &tokens, const LLSD &query_map, LLMediaCtrl* web) { LLUUID task_id = tokens[0].asUUID(); std::string name = query_map["name"].asString(); diff --git a/linden/indra/newview/llfloaterparcel.cpp b/linden/indra/newview/llfloaterparcel.cpp index 421315055..a61f3b912 100644 --- a/linden/indra/newview/llfloaterparcel.cpp +++ b/linden/indra/newview/llfloaterparcel.cpp @@ -55,7 +55,7 @@ class LLParcelHandler : public LLCommandHandler // requires trusted browser to trigger LLParcelHandler() : LLCommandHandler("parcel", true) { } bool handle(const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { if (params.size() < 2) { diff --git a/linden/indra/newview/llfloaterpostcard.cpp b/linden/indra/newview/llfloaterpostcard.cpp index aa9b2fbae..8cd552ef5 100644 --- a/linden/indra/newview/llfloaterpostcard.cpp +++ b/linden/indra/newview/llfloaterpostcard.cpp @@ -66,7 +66,7 @@ #include <boost/regex.hpp> //boost.regex lib -#include "hippoGridManager.h" +#include "hippogridmanager.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs diff --git a/linden/indra/newview/llfloaterpreference.cpp b/linden/indra/newview/llfloaterpreference.cpp index 09336cb8f..2fe4b4d98 100644 --- a/linden/indra/newview/llfloaterpreference.cpp +++ b/linden/indra/newview/llfloaterpreference.cpp @@ -64,6 +64,7 @@ #include "llpanelskins.h" #include "llprefsadvanced.h" #include "llprefschat.h" +#include "llprefscolors.h" #include "llprefsvoice.h" #include "llprefsim.h" #include "llresizehandle.h" @@ -94,7 +95,7 @@ class LLPreferencesHandler : public LLCommandHandler // requires trusted browser LLPreferencesHandler() : LLCommandHandler("preferences", true) { } bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { LLFloaterPreference::show(NULL); return true; @@ -133,9 +134,10 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * def mAudioPanel(NULL), mMsgPanel(NULL), mSkinsPanel(NULL), + mPrefsColors(NULL), mLCDPanel(NULL), - mPrefsAdvanced(NULL), - mPrefsFonts(NULL) + mPrefsFonts(NULL), + mPrefsAdvanced(NULL) { mGeneralPanel = new LLPanelGeneral(); mTabContainer->addTabPanel(mGeneralPanel, mGeneralPanel->getLabel(), FALSE, onTabChanged, mTabContainer); @@ -165,13 +167,18 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * def mTabContainer->addTabPanel(mPrefsChat->getPanel(), mPrefsChat->getPanel()->getLabel(), FALSE, onTabChanged, mTabContainer); mPrefsChat->getPanel()->setDefaultBtn(default_btn); - mPrefsVoice = new LLPrefsVoice(); - mTabContainer->addTabPanel(mPrefsVoice, mPrefsVoice->getLabel(), FALSE, onTabChanged, mTabContainer); - mPrefsVoice->setDefaultBtn(default_btn); + mPrefsColors = new LLPrefsColors(); + mTabContainer->addTabPanel(mPrefsColors, mPrefsColors->getLabel(), FALSE, onTabChanged, mTabContainer); + mPrefsColors->setDefaultBtn(default_btn); mPrefsIM = new LLPrefsIM(); mTabContainer->addTabPanel(mPrefsIM->getPanel(), mPrefsIM->getPanel()->getLabel(), FALSE, onTabChanged, mTabContainer); mPrefsIM->getPanel()->setDefaultBtn(default_btn); + + mPrefsVoice = new LLPrefsVoice(); + mTabContainer->addTabPanel(mPrefsVoice, mPrefsVoice->getLabel(), FALSE, onTabChanged, mTabContainer); + mPrefsVoice->setDefaultBtn(default_btn); + #if LL_LCD_COMPILE @@ -195,14 +202,14 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * def mTabContainer->addTabPanel(mSkinsPanel, mSkinsPanel->getLabel(), FALSE, onTabChanged, mTabContainer); mSkinsPanel->setDefaultBtn(default_btn); - mPrefsAdvanced = new LLPrefsAdvanced(); - mTabContainer->addTabPanel(mPrefsAdvanced, mPrefsAdvanced->getLabel(), FALSE, onTabChanged, mTabContainer); - mPrefsAdvanced->setDefaultBtn(default_btn); - mPrefsFonts = new ImpPrefsFonts(); mTabContainer->addTabPanel(mPrefsFonts, mPrefsFonts->getLabel(), FALSE, onTabChanged, mTabContainer); mPrefsFonts->setDefaultBtn(default_btn); + mPrefsAdvanced = new LLPrefsAdvanced(); + mTabContainer->addTabPanel(mPrefsAdvanced, mPrefsAdvanced->getLabel(), FALSE, onTabChanged, mTabContainer); + mPrefsAdvanced->setDefaultBtn(default_btn); + if (!mTabContainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) { mTabContainer->selectFirstTab(); @@ -272,7 +279,11 @@ LLPreferenceCore::~LLPreferenceCore() delete mPrefsFonts; mPrefsFonts = NULL; } - + if (mPrefsColors) + { + delete mPrefsColors; + mPrefsColors = NULL; + } } @@ -290,6 +301,7 @@ void LLPreferenceCore::apply() mSkinsPanel->apply(); mPrefsAdvanced->apply(); mPrefsFonts->apply(); + mPrefsColors->apply(); // hardware menu apply LLFloaterHardwareSettings::instance()->apply(); @@ -320,6 +332,7 @@ void LLPreferenceCore::cancel() mSkinsPanel->cancel(); mPrefsAdvanced->cancel(); mPrefsFonts->cancel(); + mPrefsColors->cancel(); // cancel hardware menu LLFloaterHardwareSettings::instance()->cancel(); @@ -445,7 +458,7 @@ void LLFloaterPreference::onBtnOK( void* userdata ) // commit any outstanding text entry if (fp->hasFocus()) { - LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus(); + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); if (cur_focus->acceptsTextInput()) { cur_focus->onCommit(); @@ -479,7 +492,7 @@ void LLFloaterPreference::onBtnApply( void* userdata ) LLFloaterPreference *fp =(LLFloaterPreference *)userdata; if (fp->hasFocus()) { - LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus(); + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); if (cur_focus->acceptsTextInput()) { cur_focus->onCommit(); @@ -505,7 +518,7 @@ void LLFloaterPreference::onBtnCancel( void* userdata ) LLFloaterPreference *fp =(LLFloaterPreference *)userdata; if (fp->hasFocus()) { - LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus(); + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); if (cur_focus->acceptsTextInput()) { cur_focus->onCommit(); diff --git a/linden/indra/newview/llfloaterpreference.h b/linden/indra/newview/llfloaterpreference.h index e98c45cc4..c52f5412c 100644 --- a/linden/indra/newview/llfloaterpreference.h +++ b/linden/indra/newview/llfloaterpreference.h @@ -57,6 +57,7 @@ class LLPanelMsgs; class LLPanelSkins; class LLPrefsAdvanced; class ImpPrefsFonts; +class LLPrefsColors; class LLScrollListCtrl; class LLPreferenceCore @@ -94,6 +95,7 @@ class LLPreferenceCore LLPanelMsgs *mMsgPanel; LLPanelLCD *mLCDPanel; LLPrefsAdvanced *mPrefsAdvanced; + LLPrefsColors *mPrefsColors; ImpPrefsFonts* mPrefsFonts; }; diff --git a/linden/indra/newview/llfloaterproperties.cpp b/linden/indra/newview/llfloaterproperties.cpp index 40b293ae1..96e164265 100644 --- a/linden/indra/newview/llfloaterproperties.cpp +++ b/linden/indra/newview/llfloaterproperties.cpp @@ -59,7 +59,7 @@ #include "lluictrlfactory.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // [RLVa:KB] #include "rlvhandler.h" diff --git a/linden/indra/newview/llfloaterregioninfo.cpp b/linden/indra/newview/llfloaterregioninfo.cpp index deee0f68b..d4ffe22bb 100644 --- a/linden/indra/newview/llfloaterregioninfo.cpp +++ b/linden/indra/newview/llfloaterregioninfo.cpp @@ -1,3298 +1,3446 @@ -/** - * @file llfloaterregioninfo.cpp - * @author Aaron Brashears - * @brief Implementation of the region info and controls floater and panels. - * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llfloaterregioninfo.h" - -#include <algorithm> -#include <functional> - -#include "llcachename.h" -#include "lldir.h" -#include "lldispatcher.h" -#include "llglheaders.h" -#include "llregionflags.h" -#include "llstl.h" -#include "indra_constants.h" -#include "message.h" - -#include "llagent.h" -#include "llalertdialog.h" -#include "llappviewer.h" -#include "llfloateravatarpicker.h" -#include "llbutton.h" -#include "llcheckboxctrl.h" -#include "llcombobox.h" -#include "llfilepicker.h" -#include "llfloaterdaycycle.h" -#include "llfloatergodtools.h" // for send_sim_wide_deletes() -#include "llfloatertopobjects.h" // added to fix SL-32336 -#include "llfloatergroups.h" -#include "llfloatertelehub.h" -#include "llfloaterwindlight.h" -#include "llinventorymodel.h" -#include "lllineeditor.h" -#include "llalertdialog.h" -#include "llnamelistctrl.h" -#include "llsliderctrl.h" -#include "llspinctrl.h" -#include "lltabcontainer.h" -#include "lltextbox.h" -#include "llinventory.h" -#include "lltexturectrl.h" -#include "lltrans.h" -#include "llviewercontrol.h" -#include "lluictrlfactory.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" -#include "llviewerregion.h" -#include "llviewerstats.h" -#include "llviewertexteditor.h" -#include "llviewerwindow.h" -#include "llvlcomposition.h" - -// [RLVa:KB] -#include "rlvhandler.h" -// [/RLVa:KB] - -#define ELAR_ENABLED 0 // Enable when server support is implemented - -const S32 TERRAIN_TEXTURE_COUNT = 4; -const S32 CORNER_COUNT = 4; - -///---------------------------------------------------------------------------- -/// Local class declaration -///---------------------------------------------------------------------------- - -class LLDispatchEstateUpdateInfo : public LLDispatchHandler -{ -public: - LLDispatchEstateUpdateInfo() {} - virtual ~LLDispatchEstateUpdateInfo() {} - virtual bool operator()( - const LLDispatcher* dispatcher, - const std::string& key, - const LLUUID& invoice, - const sparam_t& strings); -}; - -class LLDispatchSetEstateAccess : public LLDispatchHandler -{ -public: - LLDispatchSetEstateAccess() {} - virtual ~LLDispatchSetEstateAccess() {} - virtual bool operator()( - const LLDispatcher* dispatcher, - const std::string& key, - const LLUUID& invoice, - const sparam_t& strings); -}; - - -/* -void unpack_request_params( - LLMessageSystem* msg, - LLDispatcher::sparam_t& strings, - LLDispatcher::iparam_t& integers) -{ - char str_buf[MAX_STRING]; - S32 str_count = msg->getNumberOfBlocksFast(_PREHASH_StringData); - S32 i; - for (i = 0; i < str_count; ++i) - { - // we treat the SParam as binary data (since it might be an - // LLUUID in compressed form which may have embedded \0's,) - str_buf[0] = '\0'; - S32 data_size = msg->getSizeFast(_PREHASH_StringData, i, _PREHASH_SParam); - if (data_size >= 0) - { - msg->getBinaryDataFast(_PREHASH_StringData, _PREHASH_SParam, - str_buf, data_size, i, MAX_STRING - 1); - strings.push_back(std::string(str_buf, data_size)); - } - } - - U32 int_buf; - S32 int_count = msg->getNumberOfBlocksFast(_PREHASH_IntegerData); - for (i = 0; i < int_count; ++i) - { - msg->getU32("IntegerData", "IParam", int_buf, i); - integers.push_back(int_buf); - } -} -*/ - - - -bool estate_dispatch_initialized = false; - - -///---------------------------------------------------------------------------- -/// LLFloaterRegionInfo -///---------------------------------------------------------------------------- - -//S32 LLFloaterRegionInfo::sRequestSerial = 0; -LLUUID LLFloaterRegionInfo::sRequestInvoice; - -LLFloaterRegionInfo::LLFloaterRegionInfo(const LLSD& seed) -{ - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_region_info.xml", NULL, FALSE); -} - -BOOL LLFloaterRegionInfo::postBuild() -{ - mTab = getChild<LLTabContainer>("region_panels"); - - // contruct the panels - LLPanelRegionInfo* panel; - panel = new LLPanelRegionGeneralInfo; - mInfoPanels.push_back(panel); - LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_general.xml"); - mTab->addTabPanel(panel, panel->getLabel(), TRUE); - - panel = new LLPanelRegionDebugInfo; - mInfoPanels.push_back(panel); - LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_debug.xml"); - mTab->addTabPanel(panel, panel->getLabel(), FALSE); - - panel = new LLPanelRegionTextureInfo; - mInfoPanels.push_back(panel); - LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_texture.xml"); - mTab->addTabPanel(panel, panel->getLabel(), FALSE); - - panel = new LLPanelRegionTerrainInfo; - mInfoPanels.push_back(panel); - LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_terrain.xml"); - mTab->addTabPanel(panel, panel->getLabel(), FALSE); - - panel = new LLPanelEstateInfo; - mInfoPanels.push_back(panel); - LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_estate.xml"); - mTab->addTabPanel(panel, panel->getLabel(), FALSE); - - panel = new LLPanelEstateCovenant; - mInfoPanels.push_back(panel); - LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_covenant.xml"); - mTab->addTabPanel(panel, panel->getLabel(), FALSE); - - gMessageSystem->setHandlerFunc( - "EstateOwnerMessage", - &processEstateOwnerRequest); - - return TRUE; -} - -LLFloaterRegionInfo::~LLFloaterRegionInfo() -{ -} - -void LLFloaterRegionInfo::onOpen() -{ - LLRect rect = gSavedSettings.getRect("FloaterRegionInfo"); - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - rect.translate(left,top); - - refreshFromRegion(gAgent.getRegion()); - requestRegionInfo(); - LLFloater::onOpen(); -} - -// static -void LLFloaterRegionInfo::requestRegionInfo() -{ - LLTabContainer* tab = findInstance()->getChild<LLTabContainer>("region_panels"); - - tab->getChild<LLPanel>("General")->setCtrlsEnabled(FALSE); - tab->getChild<LLPanel>("Debug")->setCtrlsEnabled(FALSE); - tab->getChild<LLPanel>("Terrain")->setCtrlsEnabled(FALSE); - tab->getChild<LLPanel>("Estate")->setCtrlsEnabled(FALSE); - - // Must allow anyone to request the RegionInfo data - // so non-owners/non-gods can see the values. - // Therefore can't use an EstateOwnerMessage JC - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("RequestRegionInfo"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - gAgent.sendReliableMessage(); -} - -// static -void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) -{ - static LLDispatcher dispatch; - if(!findInstance()) - { - return; - } - - if (!estate_dispatch_initialized) - { - LLPanelEstateInfo::initDispatch(dispatch); - } - - LLTabContainer* tab = findInstance()->getChild<LLTabContainer>("region_panels"); - LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild<LLPanel>("Estate"); - - // unpack the message - std::string request; - LLUUID invoice; - LLDispatcher::sparam_t strings; - LLDispatcher::unpackMessage(msg, request, invoice, strings); - if(invoice != getLastInvoice()) - { - llwarns << "Mismatched Estate message: " << request << llendl; - return; - } - - //dispatch the message - dispatch.dispatch(request, invoice, strings); - - LLViewerRegion* region = gAgent.getRegion(); - panel->updateControls(region); -} - - -// static -void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) -{ - LLPanel* panel; - - llinfos << "LLFloaterRegionInfo::processRegionInfo" << llendl; - if(!findInstance()) - { - return; - } - - LLTabContainer* tab = findInstance()->getChild<LLTabContainer>("region_panels"); - - LLViewerRegion* region = gAgent.getRegion(); - BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); - - // extract message - std::string sim_name; - std::string sim_type = LLTrans::getString("land_type_unknown"); - U32 region_flags; - U8 agent_limit; - F32 object_bonus_factor; - U8 sim_access; - F32 water_height; - F32 terrain_raise_limit; - F32 terrain_lower_limit; - BOOL use_estate_sun; - F32 sun_hour; - msg->getString("RegionInfo", "SimName", sim_name); - msg->getU32("RegionInfo", "RegionFlags", region_flags); - msg->getU8("RegionInfo", "MaxAgents", agent_limit); - msg->getF32("RegionInfo", "ObjectBonusFactor", object_bonus_factor); - msg->getU8("RegionInfo", "SimAccess", sim_access); - msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_WaterHeight, water_height); - msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_TerrainRaiseLimit, terrain_raise_limit); - msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_TerrainLowerLimit, terrain_lower_limit); - msg->getBOOL("RegionInfo", "UseEstateSun", use_estate_sun); - // actually the "last set" sun hour, not the current sun hour. JC - msg->getF32("RegionInfo", "SunHour", sun_hour); - // the only reasonable way to decide if we actually have any data is to - // check to see if any of these fields have nonzero sizes - if (msg->getSize("RegionInfo2", "ProductSKU") > 0 || - msg->getSize("RegionInfo2", "ProductName") > 0) - { - msg->getString("RegionInfo2", "ProductName", sim_type); - } - - // GENERAL PANEL - panel = tab->getChild<LLPanel>("General"); - panel->childSetValue("region_text", LLSD(sim_name)); - panel->childSetValue("region_type", LLSD(sim_type)); - panel->childSetValue("version_channel_text", gLastVersionChannel); - - panel->childSetValue("block_terraform_check", (region_flags & REGION_FLAGS_BLOCK_TERRAFORM) ? TRUE : FALSE ); - panel->childSetValue("block_fly_check", (region_flags & REGION_FLAGS_BLOCK_FLY) ? TRUE : FALSE ); - panel->childSetValue("allow_damage_check", (region_flags & REGION_FLAGS_ALLOW_DAMAGE) ? TRUE : FALSE ); - panel->childSetValue("restrict_pushobject", (region_flags & REGION_FLAGS_RESTRICT_PUSHOBJECT) ? TRUE : FALSE ); - panel->childSetValue("allow_land_resell_check", (region_flags & REGION_FLAGS_BLOCK_LAND_RESELL) ? FALSE : TRUE ); - panel->childSetValue("allow_parcel_changes_check", (region_flags & REGION_FLAGS_ALLOW_PARCEL_CHANGES) ? TRUE : FALSE ); - panel->childSetValue("block_parcel_search_check", (region_flags & REGION_FLAGS_BLOCK_PARCEL_SEARCH) ? TRUE : FALSE ); - panel->childSetValue("agent_limit_spin", LLSD((F32)agent_limit) ); - panel->childSetValue("object_bonus_spin", LLSD(object_bonus_factor) ); - panel->childSetValue("access_combo", LLSD(sim_access) ); - - - // detect teen grid for maturity - - U32 parent_estate_id; - msg->getU32("RegionInfo", "ParentEstateID", parent_estate_id); - BOOL teen_grid = (parent_estate_id == 5); // *TODO add field to estate table and test that - panel->childSetEnabled("access_combo", gAgent.isGodlike() || (region && region->canManageEstate() && !teen_grid)); - panel->setCtrlsEnabled(allow_modify); - - - // DEBUG PANEL - panel = tab->getChild<LLPanel>("Debug"); - - panel->childSetValue("region_text", LLSD(sim_name) ); - panel->childSetValue("disable_scripts_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SKIP_SCRIPTS)) ); - panel->childSetValue("disable_collisions_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SKIP_COLLISIONS)) ); - panel->childSetValue("disable_physics_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SKIP_PHYSICS)) ); - panel->setCtrlsEnabled(allow_modify); - - // TERRAIN PANEL - panel = tab->getChild<LLPanel>("Terrain"); - - panel->childSetValue("region_text", LLSD(sim_name)); - panel->childSetValue("water_height_spin", LLSD(water_height)); - panel->childSetValue("terrain_raise_spin", LLSD(terrain_raise_limit)); - panel->childSetValue("terrain_lower_spin", LLSD(terrain_lower_limit)); - panel->childSetValue("use_estate_sun_check", LLSD(use_estate_sun)); - - panel->childSetValue("fixed_sun_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SUN_FIXED))); - panel->childSetEnabled("fixed_sun_check", allow_modify && !use_estate_sun); - panel->childSetValue("sun_hour_slider", LLSD(sun_hour)); - panel->childSetEnabled("sun_hour_slider", allow_modify && !use_estate_sun); - panel->setCtrlsEnabled(allow_modify); - - getInstance()->refreshFromRegion( gAgent.getRegion() ); -} - -// static -LLPanelEstateInfo* LLFloaterRegionInfo::getPanelEstate() -{ - LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); - if (!floater) return NULL; - LLTabContainer* tab = floater->getChild<LLTabContainer>("region_panels"); - LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild<LLPanel>("Estate"); - return panel; -} - -// static -LLPanelEstateCovenant* LLFloaterRegionInfo::getPanelCovenant() -{ - LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); - if (!floater) return NULL; - LLTabContainer* tab = floater->getChild<LLTabContainer>("region_panels"); - LLPanelEstateCovenant* panel = (LLPanelEstateCovenant*)tab->getChild<LLPanel>("Covenant"); - return panel; -} - -void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region) -{ - // call refresh from region on all panels - std::for_each( - mInfoPanels.begin(), - mInfoPanels.end(), - llbind2nd( -#if LL_WINDOWS - std::mem_fun1(&LLPanelRegionInfo::refreshFromRegion), -#else - std::mem_fun(&LLPanelRegionInfo::refreshFromRegion), -#endif - region)); -} - -// public -void LLFloaterRegionInfo::refresh() -{ - for(info_panels_t::iterator iter = mInfoPanels.begin(); - iter != mInfoPanels.end(); ++iter) - { - (*iter)->refresh(); - } -} - - -///---------------------------------------------------------------------------- -/// Local class implementation -///---------------------------------------------------------------------------- - -// -// LLPanelRegionInfo -// - -// static -void LLPanelRegionInfo::onBtnSet(void* user_data) -{ - LLPanelRegionInfo* panel = (LLPanelRegionInfo*)user_data; - if(!panel) return; - if (panel->sendUpdate()) - { - panel->disableButton("apply_btn"); - } -} - -//static -void LLPanelRegionInfo::onChangeChildCtrl(LLUICtrl* ctrl, void* user_data) -{ - if (ctrl) - { - LLPanelRegionInfo* panel = (LLPanelRegionInfo*) ctrl->getParent(); - panel->updateChild(ctrl); - } -} - -// static -// Enables the "set" button if it is not already enabled -void LLPanelRegionInfo::onChangeAnything(LLUICtrl* ctrl, void* user_data) -{ - LLPanelRegionInfo* panel = (LLPanelRegionInfo*)user_data; - if(panel) - { - panel->enableButton("apply_btn"); - panel->refresh(); - } -} - -// static -// Enables set button on change to line editor -void LLPanelRegionInfo::onChangeText(LLLineEditor* caller, void* user_data) -{ - // reuse the previous method - onChangeAnything(0, user_data); -} - - -// virtual -BOOL LLPanelRegionInfo::postBuild() -{ - childSetAction("apply_btn", onBtnSet, this); - childDisable("apply_btn"); - refresh(); - return TRUE; -} - -// virtual -void LLPanelRegionInfo::updateChild(LLUICtrl* child_ctr) -{ -} - -// virtual -bool LLPanelRegionInfo::refreshFromRegion(LLViewerRegion* region) -{ - if (region) mHost = region->getHost(); - return true; -} - -void LLPanelRegionInfo::sendEstateOwnerMessage( - LLMessageSystem* msg, - const std::string& request, - const LLUUID& invoice, - const strings_t& strings) -{ - llinfos << "Sending estate request '" << request << "'" << llendl; - msg->newMessage("EstateOwnerMessage"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used - msg->nextBlock("MethodData"); - msg->addString("Method", request); - msg->addUUID("Invoice", invoice); - if(strings.empty()) - { - msg->nextBlock("ParamList"); - msg->addString("Parameter", NULL); - } - else - { - strings_t::const_iterator it = strings.begin(); - strings_t::const_iterator end = strings.end(); - for(; it != end; ++it) - { - msg->nextBlock("ParamList"); - msg->addString("Parameter", *it); - } - } - msg->sendReliable(mHost); -} - -void LLPanelRegionInfo::enableButton(const std::string& btn_name, BOOL enable) -{ - childSetEnabled(btn_name, enable); -} - -void LLPanelRegionInfo::disableButton(const std::string& btn_name) -{ - childDisable(btn_name); -} - -void LLPanelRegionInfo::initCtrl(const std::string& name) -{ - childSetCommitCallback(name, onChangeAnything, this); -} - -void LLPanelRegionInfo::initHelpBtn(const std::string& name, const std::string& xml_alert) -{ - childSetAction(name, onClickHelp, new std::string(xml_alert)); -} - -// static -void LLPanelRegionInfo::onClickHelp(void* data) -{ - std::string* xml_alert = (std::string*)data; - LLNotifications::instance().add(*xml_alert); -} - -///////////////////////////////////////////////////////////////////////////// -// LLPanelRegionGeneralInfo -// -bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region) -{ - BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); - setCtrlsEnabled(allow_modify); - childDisable("apply_btn"); - childSetEnabled("access_text", allow_modify); - // childSetEnabled("access_combo", allow_modify); - // now set in processRegionInfo for teen grid detection - childSetEnabled("kick_btn", allow_modify); - childSetEnabled("kick_all_btn", allow_modify); - childSetEnabled("im_btn", allow_modify); - childSetEnabled("manage_telehub_btn", allow_modify); - - // Data gets filled in by processRegionInfo - - return LLPanelRegionInfo::refreshFromRegion(region); -} - -BOOL LLPanelRegionGeneralInfo::postBuild() -{ - // Enable the "Apply" button if something is changed. JC - initCtrl("block_terraform_check"); - initCtrl("block_fly_check"); - initCtrl("allow_damage_check"); - initCtrl("allow_land_resell_check"); - initCtrl("allow_parcel_changes_check"); - initCtrl("agent_limit_spin"); - initCtrl("object_bonus_spin"); - initCtrl("access_combo"); - initCtrl("restrict_pushobject"); - initCtrl("block_parcel_search_check"); - - initHelpBtn("terraform_help", "HelpRegionBlockTerraform"); - initHelpBtn("fly_help", "HelpRegionBlockFly"); - initHelpBtn("damage_help", "HelpRegionAllowDamage"); - initHelpBtn("agent_limit_help", "HelpRegionAgentLimit"); - initHelpBtn("object_bonus_help", "HelpRegionObjectBonus"); - initHelpBtn("access_help", "HelpRegionMaturity"); - initHelpBtn("restrict_pushobject_help", "HelpRegionRestrictPushObject"); - initHelpBtn("land_resell_help", "HelpRegionLandResell"); - initHelpBtn("parcel_changes_help", "HelpParcelChanges"); - initHelpBtn("parcel_search_help", "HelpRegionSearch"); - - childSetAction("kick_btn", onClickKick, this); - childSetAction("kick_all_btn", onClickKickAll, this); - childSetAction("im_btn", onClickMessage, this); - childSetAction("manage_telehub_btn", onClickManageTelehub, this); - - return LLPanelRegionInfo::postBuild(); -} - -// static -void LLPanelRegionGeneralInfo::onClickKick(void* userdata) -{ - llinfos << "LLPanelRegionGeneralInfo::onClickKick" << llendl; - LLPanelRegionGeneralInfo* panelp = (LLPanelRegionGeneralInfo*)userdata; - - // this depends on the grandparent view being a floater - // in order to set up floater dependency - LLFloater* parent_floater = gFloaterView->getParentFloater(panelp); - LLFloater* child_floater = LLFloaterAvatarPicker::show(onKickCommit, userdata, FALSE, TRUE); - parent_floater->addDependentFloater(child_floater); -} - -// static -void LLPanelRegionGeneralInfo::onKickCommit(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* userdata) -{ - if (names.empty() || ids.empty()) return; - if(ids[0].notNull()) - { - LLPanelRegionGeneralInfo* self = (LLPanelRegionGeneralInfo*)userdata; - if(!self) return; - strings_t strings; - // [0] = our agent id - // [1] = target agent id - std::string buffer; - gAgent.getID().toString(buffer); - strings.push_back(buffer); - - ids[0].toString(buffer); - strings.push_back(strings_t::value_type(buffer)); - - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "teleporthomeuser", invoice, strings); - } -} - -// static -void LLPanelRegionGeneralInfo::onClickKickAll(void* userdata) -{ - llinfos << "LLPanelRegionGeneralInfo::onClickKickAll" << llendl; - LLNotifications::instance().add("KickUsersFromRegion", - LLSD(), - LLSD(), - boost::bind(&LLPanelRegionGeneralInfo::onKickAllCommit, (LLPanelRegionGeneralInfo*)userdata, _1, _2)); -} - -bool LLPanelRegionGeneralInfo::onKickAllCommit(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0) - { - strings_t strings; - // [0] = our agent id - std::string buffer; - gAgent.getID().toString(buffer); - strings.push_back(buffer); - - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - // historical message name - sendEstateOwnerMessage(gMessageSystem, "teleporthomeallusers", invoice, strings); - } - return false; -} - -// static -void LLPanelRegionGeneralInfo::onClickMessage(void* userdata) -{ - llinfos << "LLPanelRegionGeneralInfo::onClickMessage" << llendl; - LLNotifications::instance().add("MessageRegion", - LLSD(), - LLSD(), - boost::bind(&LLPanelRegionGeneralInfo::onMessageCommit, (LLPanelRegionGeneralInfo*)userdata, _1, _2)); -} - -// static -bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const LLSD& response) -{ - if(LLNotification::getSelectedOption(notification, response) != 0) return false; - - std::string text = response["message"].asString(); - if (text.empty()) return false; - - llinfos << "Message to everyone: " << text << llendl; - strings_t strings; - // [0] grid_x, unused here - // [1] grid_y, unused here - // [2] agent_id of sender - // [3] sender name - // [4] message - strings.push_back("-1"); - strings.push_back("-1"); - std::string buffer; - gAgent.getID().toString(buffer); - strings.push_back(buffer); - std::string name; - gAgent.buildFullname(name); - strings.push_back(strings_t::value_type(name)); - strings.push_back(strings_t::value_type(text)); - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - sendEstateOwnerMessage(gMessageSystem, "simulatormessage", invoice, strings); - return false; -} - -// static -void LLPanelRegionGeneralInfo::onClickManageTelehub(void* data) -{ - LLFloaterRegionInfo::getInstance()->close(); - - LLFloaterTelehub::show(); -} - -// setregioninfo -// strings[0] = 'Y' - block terraform, 'N' - not -// strings[1] = 'Y' - block fly, 'N' - not -// strings[2] = 'Y' - allow damage, 'N' - not -// strings[3] = 'Y' - allow land sale, 'N' - not -// strings[4] = agent limit -// strings[5] = object bonus -// strings[6] = sim access (0 = unknown, 13 = PG, 21 = Mature, 42 = Adult) -// strings[7] = restrict pushobject -// strings[8] = 'Y' - allow parcel subdivide, 'N' - not -// strings[9] = 'Y' - block parcel search, 'N' - allow -BOOL LLPanelRegionGeneralInfo::sendUpdate() -{ - llinfos << "LLPanelRegionGeneralInfo::sendUpdate()" << llendl; - - // First try using a Cap. If that fails use the old method. - LLSD body; - std::string url = gAgent.getRegion()->getCapability("DispatchRegionInfo"); - if (!url.empty()) - { - body["block_terraform"] = childGetValue("block_terraform_check"); - body["block_fly"] = childGetValue("block_fly_check"); - body["allow_damage"] = childGetValue("allow_damage_check"); - body["allow_land_resell"] = childGetValue("allow_land_resell_check"); - body["agent_limit"] = childGetValue("agent_limit_spin"); - body["prim_bonus"] = childGetValue("object_bonus_spin"); - body["sim_access"] = childGetValue("access_combo"); - body["restrict_pushobject"] = childGetValue("restrict_pushobject"); - body["allow_parcel_changes"] = childGetValue("allow_parcel_changes_check"); - body["block_parcel_search"] = childGetValue("block_parcel_search_check"); - - LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); - } - else - { - strings_t strings; - std::string buffer; - - buffer = llformat("%s", (childGetValue("block_terraform_check").asBoolean() ? "Y" : "N")); - strings.push_back(strings_t::value_type(buffer)); - - buffer = llformat("%s", (childGetValue("block_fly_check").asBoolean() ? "Y" : "N")); - strings.push_back(strings_t::value_type(buffer)); - - buffer = llformat("%s", (childGetValue("allow_damage_check").asBoolean() ? "Y" : "N")); - strings.push_back(strings_t::value_type(buffer)); - - buffer = llformat("%s", (childGetValue("allow_land_resell_check").asBoolean() ? "Y" : "N")); - strings.push_back(strings_t::value_type(buffer)); - - F32 value = (F32)childGetValue("agent_limit_spin").asReal(); - buffer = llformat("%f", value); - strings.push_back(strings_t::value_type(buffer)); - - value = (F32)childGetValue("object_bonus_spin").asReal(); - buffer = llformat("%f", value); - strings.push_back(strings_t::value_type(buffer)); - - buffer = llformat("%d", childGetValue("access_combo").asInteger()); - strings.push_back(strings_t::value_type(buffer)); - - buffer = llformat("%s", (childGetValue("restrict_pushobject").asBoolean() ? "Y" : "N")); - strings.push_back(strings_t::value_type(buffer)); - - buffer = llformat("%s", (childGetValue("allow_parcel_changes_check").asBoolean() ? "Y" : "N")); - strings.push_back(strings_t::value_type(buffer)); - - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - sendEstateOwnerMessage(gMessageSystem, "setregioninfo", invoice, strings); - } - - // if we changed access levels, tell user about it - LLViewerRegion* region = gAgent.getRegion(); - if (region && (childGetValue("access_combo").asInteger() != region->getSimAccess()) ) - { - LLNotifications::instance().add("RegionMaturityChange"); - } - - return TRUE; -} - -///////////////////////////////////////////////////////////////////////////// -// LLPanelRegionDebugInfo -///////////////////////////////////////////////////////////////////////////// -BOOL LLPanelRegionDebugInfo::postBuild() -{ - LLPanelRegionInfo::postBuild(); - initCtrl("disable_scripts_check"); - initCtrl("disable_collisions_check"); - initCtrl("disable_physics_check"); - - initHelpBtn("disable_scripts_help", "HelpRegionDisableScripts"); - initHelpBtn("disable_collisions_help", "HelpRegionDisableCollisions"); - initHelpBtn("disable_physics_help", "HelpRegionDisablePhysics"); - initHelpBtn("top_colliders_help", "HelpRegionTopColliders"); - initHelpBtn("top_scripts_help", "HelpRegionTopScripts"); - initHelpBtn("restart_help", "HelpRegionRestart"); - - childSetAction("choose_avatar_btn", onClickChooseAvatar, this); - childSetAction("return_btn", onClickReturn, this); - childSetAction("top_colliders_btn", onClickTopColliders, this); - childSetAction("top_scripts_btn", onClickTopScripts, this); - childSetAction("restart_btn", onClickRestart, this); - childSetAction("cancel_restart_btn", onClickCancelRestart, this); - - return TRUE; -} - -// virtual -bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region) -{ - BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); - setCtrlsEnabled(allow_modify); - childDisable("apply_btn"); - childDisable("target_avatar_name"); - - childSetEnabled("choose_avatar_btn", allow_modify); - childSetEnabled("return_scripts", allow_modify && !mTargetAvatar.isNull()); - childSetEnabled("return_other_land", allow_modify && !mTargetAvatar.isNull()); - childSetEnabled("return_estate_wide", allow_modify && !mTargetAvatar.isNull()); - childSetEnabled("return_btn", allow_modify && !mTargetAvatar.isNull()); - childSetEnabled("top_colliders_btn", allow_modify); - childSetEnabled("top_scripts_btn", allow_modify); - childSetEnabled("restart_btn", allow_modify); - childSetEnabled("cancel_restart_btn", allow_modify); - - return LLPanelRegionInfo::refreshFromRegion(region); -} - -// virtual -BOOL LLPanelRegionDebugInfo::sendUpdate() -{ - llinfos << "LLPanelRegionDebugInfo::sendUpdate" << llendl; - strings_t strings; - std::string buffer; - - buffer = llformat("%s", (childGetValue("disable_scripts_check").asBoolean() ? "Y" : "N")); - strings.push_back(buffer); - - buffer = llformat("%s", (childGetValue("disable_collisions_check").asBoolean() ? "Y" : "N")); - strings.push_back(buffer); - - buffer = llformat("%s", (childGetValue("disable_physics_check").asBoolean() ? "Y" : "N")); - strings.push_back(buffer); - - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - sendEstateOwnerMessage(gMessageSystem, "setregiondebug", invoice, strings); - return TRUE; -} - -void LLPanelRegionDebugInfo::onClickChooseAvatar(void* data) -{ - LLFloaterAvatarPicker::show(callbackAvatarID, data, FALSE, TRUE); -} - -// static -void LLPanelRegionDebugInfo::callbackAvatarID(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* data) -{ - LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*) data; - if (ids.empty() || names.empty()) return; - self->mTargetAvatar = ids[0]; - self->childSetValue("target_avatar_name", LLSD(names[0])); - self->refreshFromRegion( gAgent.getRegion() ); -} - -// static -void LLPanelRegionDebugInfo::onClickReturn(void* data) -{ - LLPanelRegionDebugInfo* panelp = (LLPanelRegionDebugInfo*) data; - if (panelp->mTargetAvatar.isNull()) return; - - LLSD args; - args["USER_NAME"] = panelp->childGetValue("target_avatar_name").asString(); - LLSD payload; - payload["avatar_id"] = panelp->mTargetAvatar; - - U32 flags = SWD_ALWAYS_RETURN_OBJECTS; - - if (panelp->childGetValue("return_scripts").asBoolean()) - { - flags |= SWD_SCRIPTED_ONLY; - } - - if (panelp->childGetValue("return_other_land").asBoolean()) - { - flags |= SWD_OTHERS_LAND_ONLY; - } - payload["flags"] = int(flags); - payload["return_estate_wide"] = panelp->childGetValue("return_estate_wide").asBoolean(); - LLNotifications::instance().add("EstateObjectReturn", args, payload, - boost::bind(&LLPanelRegionDebugInfo::callbackReturn, panelp, _1, _2)); -} - -bool LLPanelRegionDebugInfo::callbackReturn(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option != 0) return false; - - LLUUID target_avatar = notification["payload"]["avatar_id"].asUUID(); - if (!target_avatar.isNull()) - { - U32 flags = notification["payload"]["flags"].asInteger(); - bool return_estate_wide = notification["payload"]["return_estate_wide"]; - if (return_estate_wide) - { - // send as estate message - routed by spaceserver to all regions in estate - strings_t strings; - strings.push_back(llformat("%d", flags)); - strings.push_back(target_avatar.asString()); - - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - - sendEstateOwnerMessage(gMessageSystem, "estateobjectreturn", invoice, strings); - } - else - { - // send to this simulator only - send_sim_wide_deletes(target_avatar, flags); - } - } - return false; -} - - -// static -void LLPanelRegionDebugInfo::onClickTopColliders(void* data) -{ - LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*)data; - strings_t strings; - strings.push_back("1"); // one physics step - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - LLFloaterTopObjects::show(); - LLFloaterTopObjects::clearList(); - self->sendEstateOwnerMessage(gMessageSystem, "colliders", invoice, strings); -} - -// static -void LLPanelRegionDebugInfo::onClickTopScripts(void* data) -{ - LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*)data; - strings_t strings; - strings.push_back("6"); // top 5 scripts - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - LLFloaterTopObjects::show(); - LLFloaterTopObjects::clearList(); - self->sendEstateOwnerMessage(gMessageSystem, "scripts", invoice, strings); -} - -// static -void LLPanelRegionDebugInfo::onClickRestart(void* data) -{ - LLNotifications::instance().add("ConfirmRestart", LLSD(), LLSD(), - boost::bind(&LLPanelRegionDebugInfo::callbackRestart, (LLPanelRegionDebugInfo*)data, _1, _2)); -} - -bool LLPanelRegionDebugInfo::callbackRestart(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option != 0) return false; - - strings_t strings; - strings.push_back("120"); - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - sendEstateOwnerMessage(gMessageSystem, "restart", invoice, strings); - return false; -} - -// static -void LLPanelRegionDebugInfo::onClickCancelRestart(void* data) -{ - LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*)data; - strings_t strings; - strings.push_back("-1"); - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "restart", invoice, strings); -} - - -///////////////////////////////////////////////////////////////////////////// -// LLPanelRegionTextureInfo -// -LLPanelRegionTextureInfo::LLPanelRegionTextureInfo() : LLPanelRegionInfo() -{ - // nothing. -} - -bool LLPanelRegionTextureInfo::refreshFromRegion(LLViewerRegion* region) -{ - BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); - setCtrlsEnabled(allow_modify); - childDisable("apply_btn"); - - if (region) - { - childSetValue("region_text", LLSD(region->getName())); - } - else - { - childSetValue("region_text", LLSD("")); - } - - if (!region) return LLPanelRegionInfo::refreshFromRegion(region); - - LLVLComposition* compp = region->getComposition(); - LLTextureCtrl* texture_ctrl; - std::string buffer; - for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) - { - buffer = llformat("texture_detail_%d", i); - texture_ctrl = getChild<LLTextureCtrl>(buffer); - if(texture_ctrl) - { - lldebugs << "Detail Texture " << i << ": " - << compp->getDetailTextureID(i) << llendl; - LLUUID tmp_id(compp->getDetailTextureID(i)); - texture_ctrl->setImageAssetID(tmp_id); - } - } - - for(S32 i = 0; i < CORNER_COUNT; ++i) - { - buffer = llformat("height_start_spin_%d", i); - childSetValue(buffer, LLSD(compp->getStartHeight(i))); - buffer = llformat("height_range_spin_%d", i); - childSetValue(buffer, LLSD(compp->getHeightRange(i))); - } - - // Call the parent for common book-keeping - return LLPanelRegionInfo::refreshFromRegion(region); -} - - -BOOL LLPanelRegionTextureInfo::postBuild() -{ - LLPanelRegionInfo::postBuild(); - std::string buffer; - for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) - { - buffer = llformat("texture_detail_%d", i); - initCtrl(buffer); - } - - for(S32 i = 0; i < CORNER_COUNT; ++i) - { - buffer = llformat("height_start_spin_%d", i); - initCtrl(buffer); - buffer = llformat("height_range_spin_%d", i); - initCtrl(buffer); - } - -// LLButton* btn = new LLButton("dump", LLRect(0, 20, 100, 0), "", onClickDump, this); -// btn->setFollows(FOLLOWS_TOP|FOLLOWS_LEFT); -// addChild(btn); - - return LLPanelRegionInfo::postBuild(); -} - -BOOL LLPanelRegionTextureInfo::sendUpdate() -{ - llinfos << "LLPanelRegionTextureInfo::sendUpdate()" << llendl; - - // Make sure user hasn't chosen wacky textures. - if (!validateTextureSizes()) - { - return FALSE; - } - - LLTextureCtrl* texture_ctrl; - std::string buffer; - std::string id_str; - LLMessageSystem* msg = gMessageSystem; - strings_t strings; - - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - - for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) - { - buffer = llformat("texture_detail_%d", i); - texture_ctrl = getChild<LLTextureCtrl>(buffer); - if(texture_ctrl) - { - LLUUID tmp_id(texture_ctrl->getImageAssetID()); - tmp_id.toString(id_str); - buffer = llformat("%d %s", i, id_str.c_str()); - strings.push_back(buffer); - } - } - sendEstateOwnerMessage(msg, "texturedetail", invoice, strings); - strings.clear(); - for(S32 i = 0; i < CORNER_COUNT; ++i) - { - buffer = llformat("height_start_spin_%d", i); - std::string buffer2 = llformat("height_range_spin_%d", i); - std::string buffer3 = llformat("%d %f %f", i, (F32)childGetValue(buffer).asReal(), (F32)childGetValue(buffer2).asReal()); - strings.push_back(buffer3); - } - sendEstateOwnerMessage(msg, "textureheights", invoice, strings); - strings.clear(); - sendEstateOwnerMessage(msg, "texturecommit", invoice, strings); - return TRUE; -} - -BOOL LLPanelRegionTextureInfo::validateTextureSizes() -{ - for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) - { - std::string buffer; - buffer = llformat("texture_detail_%d", i); - LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>(buffer); - if (!texture_ctrl) continue; - - LLUUID image_asset_id = texture_ctrl->getImageAssetID(); - LLViewerImage* img = gImageList.getImage(image_asset_id); - S32 components = img->getComponents(); - // Must ask for highest resolution version's width. JC - S32 width = img->getWidth(0); - S32 height = img->getHeight(0); - - //llinfos << "texture detail " << i << " is " << width << "x" << height << "x" << components << llendl; - - if (components != 3) - { - LLSD args; - args["TEXTURE_NUM"] = i+1; - args["TEXTURE_BIT_DEPTH"] = llformat("%d",components * 8); - LLNotifications::instance().add("InvalidTerrainBitDepth", args); - return FALSE; - } - - if (width > 512 || height > 512) - { - - LLSD args; - args["TEXTURE_NUM"] = i+1; - args["TEXTURE_SIZE_X"] = width; - args["TEXTURE_SIZE_Y"] = height; - LLNotifications::instance().add("InvalidTerrainSize", args); - return FALSE; - - } - } - - return TRUE; -} - - -// static -void LLPanelRegionTextureInfo::onClickDump(void* data) -{ - llinfos << "LLPanelRegionTextureInfo::onClickDump()" << llendl; -} - - -///////////////////////////////////////////////////////////////////////////// -// LLPanelRegionTerrainInfo -///////////////////////////////////////////////////////////////////////////// -BOOL LLPanelRegionTerrainInfo::postBuild() -{ - LLPanelRegionInfo::postBuild(); - - initHelpBtn("water_height_help", "HelpRegionWaterHeight"); - initHelpBtn("terrain_raise_help", "HelpRegionTerrainRaise"); - initHelpBtn("terrain_lower_help", "HelpRegionTerrainLower"); - initHelpBtn("upload_raw_help", "HelpRegionUploadRaw"); - initHelpBtn("download_raw_help", "HelpRegionDownloadRaw"); - initHelpBtn("use_estate_sun_help", "HelpRegionUseEstateSun"); - initHelpBtn("fixed_sun_help", "HelpRegionFixedSun"); - initHelpBtn("bake_terrain_help", "HelpRegionBakeTerrain"); - - initCtrl("water_height_spin"); - initCtrl("terrain_raise_spin"); - initCtrl("terrain_lower_spin"); - - initCtrl("fixed_sun_check"); - childSetCommitCallback("fixed_sun_check", onChangeFixedSun, this); - childSetCommitCallback("use_estate_sun_check", onChangeUseEstateTime, this); - childSetCommitCallback("sun_hour_slider", onChangeSunHour, this); - - childSetAction("download_raw_btn", onClickDownloadRaw, this); - childSetAction("upload_raw_btn", onClickUploadRaw, this); - childSetAction("bake_terrain_btn", onClickBakeTerrain, this); - - return TRUE; -} - -// virtual -bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) -{ - llinfos << "LLPanelRegionTerrainInfo::refreshFromRegion" << llendl; - - BOOL owner_or_god = gAgent.isGodlike() - || (region && (region->getOwner() == gAgent.getID())); - BOOL owner_or_god_or_manager = owner_or_god - || (region && region->isEstateManager()); - setCtrlsEnabled(owner_or_god_or_manager); - childDisable("apply_btn"); - - childSetEnabled("download_raw_btn", owner_or_god); - childSetEnabled("upload_raw_btn", owner_or_god); - childSetEnabled("bake_terrain_btn", owner_or_god); - - return LLPanelRegionInfo::refreshFromRegion(region); -} - -// virtual -BOOL LLPanelRegionTerrainInfo::sendUpdate() -{ - llinfos << "LLPanelRegionTerrainInfo::sendUpdate" << llendl; - std::string buffer; - strings_t strings; - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - - buffer = llformat("%f", (F32)childGetValue("water_height_spin").asReal()); - strings.push_back(buffer); - buffer = llformat("%f", (F32)childGetValue("terrain_raise_spin").asReal()); - strings.push_back(buffer); - buffer = llformat("%f", (F32)childGetValue("terrain_lower_spin").asReal()); - strings.push_back(buffer); - buffer = llformat("%s", (childGetValue("use_estate_sun_check").asBoolean() ? "Y" : "N")); - strings.push_back(buffer); - buffer = llformat("%s", (childGetValue("fixed_sun_check").asBoolean() ? "Y" : "N")); - strings.push_back(buffer); - buffer = llformat("%f", (F32)childGetValue("sun_hour_slider").asReal() ); - strings.push_back(buffer); - - // Grab estate information in case the user decided to set the - // region back to estate time. JC - LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); - if (!floater) return true; - - LLTabContainer* tab = floater->getChild<LLTabContainer>("region_panels"); - if (!tab) return true; - - LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild<LLPanel>("Estate"); - if (!panel) return true; - - BOOL estate_global_time = panel->getGlobalTime(); - BOOL estate_fixed_sun = panel->getFixedSun(); - F32 estate_sun_hour; - if (estate_global_time) - { - estate_sun_hour = 0.f; - } - else - { - estate_sun_hour = panel->getSunHour(); - } - - buffer = llformat("%s", (estate_global_time ? "Y" : "N") ); - strings.push_back(buffer); - buffer = llformat("%s", (estate_fixed_sun ? "Y" : "N") ); - strings.push_back(buffer); - buffer = llformat("%f", estate_sun_hour); - strings.push_back(buffer); - - sendEstateOwnerMessage(gMessageSystem, "setregionterrain", invoice, strings); - return TRUE; -} - -// static -void LLPanelRegionTerrainInfo::onChangeUseEstateTime(LLUICtrl* ctrl, void* user_data) -{ - LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) user_data; - if (!panel) return; - BOOL use_estate_sun = panel->childGetValue("use_estate_sun_check").asBoolean(); - panel->childSetEnabled("fixed_sun_check", !use_estate_sun); - panel->childSetEnabled("sun_hour_slider", !use_estate_sun); - if (use_estate_sun) - { - panel->childSetValue("fixed_sun_check", LLSD(FALSE)); - panel->childSetValue("sun_hour_slider", LLSD(0.f)); - } - panel->childEnable("apply_btn"); -} - -// static -void LLPanelRegionTerrainInfo::onChangeFixedSun(LLUICtrl* ctrl, void* user_data) -{ - LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) user_data; - if (!panel) return; - // Just enable the apply button. We let the sun-hour slider be enabled - // for both fixed-sun and non-fixed-sun. JC - panel->childEnable("apply_btn"); -} - -// static -void LLPanelRegionTerrainInfo::onChangeSunHour(LLUICtrl* ctrl, void*) -{ - // can't use userdata to get panel, slider uses it internally - LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) ctrl->getParent(); - if (!panel) return; - panel->childEnable("apply_btn"); -} - -// static -void LLPanelRegionTerrainInfo::onClickDownloadRaw(void* data) -{ - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getSaveFile(LLFilePicker::FFSAVE_RAW, "terrain.raw")) - { - llwarns << "No file" << llendl; - return; - } - std::string filepath = picker.getFirstFile(); - gXferManager->expectFileForRequest(filepath); - - LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; - strings_t strings; - strings.push_back("download filename"); - strings.push_back(filepath); - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); -} - -// static -void LLPanelRegionTerrainInfo::onClickUploadRaw(void* data) -{ - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getOpenFile(LLFilePicker::FFLOAD_RAW)) - { - llwarns << "No file" << llendl; - return; - } - std::string filepath = picker.getFirstFile(); - gXferManager->expectFileForTransfer(filepath); - - LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; - strings_t strings; - strings.push_back("upload filename"); - strings.push_back(filepath); - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); - - LLNotifications::instance().add("RawUploadStarted"); -} - -// static -void LLPanelRegionTerrainInfo::onClickBakeTerrain(void* data) -{ - LLNotifications::instance().add( - LLNotification::Params("ConfirmBakeTerrain") - .functor(boost::bind(&LLPanelRegionTerrainInfo::callbackBakeTerrain, (LLPanelRegionTerrainInfo*)data, _1, _2))); -} - -bool LLPanelRegionTerrainInfo::callbackBakeTerrain(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option != 0) return false; - - strings_t strings; - strings.push_back("bake"); - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); - return false; -} - -///////////////////////////////////////////////////////////////////////////// -// LLPanelEstateInfo -// - -LLPanelEstateInfo::LLPanelEstateInfo() -: LLPanelRegionInfo(), - mEstateID(0) // invalid -{ -} - -// static -void LLPanelEstateInfo::initDispatch(LLDispatcher& dispatch) -{ - std::string name; - -// name.assign("setowner"); -// static LLDispatchSetEstateOwner set_owner; -// dispatch.addHandler(name, &set_owner); - - name.assign("estateupdateinfo"); - static LLDispatchEstateUpdateInfo estate_update_info; - dispatch.addHandler(name, &estate_update_info); - - name.assign("setaccess"); - static LLDispatchSetEstateAccess set_access; - dispatch.addHandler(name, &set_access); - - estate_dispatch_initialized = true; -} - -// static -// Disables the sun-hour slider and the use fixed time check if the use global time is check -void LLPanelEstateInfo::onChangeUseGlobalTime(LLUICtrl* ctrl, void* user_data) -{ - LLPanelEstateInfo* panel = (LLPanelEstateInfo*) user_data; - if (panel) - { - bool enabled = !panel->childGetValue("use_global_time_check").asBoolean(); - panel->childSetEnabled("sun_hour_slider", enabled); - panel->childSetEnabled("fixed_sun_check", enabled); - panel->childSetValue("fixed_sun_check", LLSD(FALSE)); - panel->enableButton("apply_btn"); - } -} - -// Enables the sun-hour slider if the fixed-sun checkbox is set -void LLPanelEstateInfo::onChangeFixedSun(LLUICtrl* ctrl, void* user_data) -{ - LLPanelEstateInfo* panel = (LLPanelEstateInfo*) user_data; - if (panel) - { - bool enabled = !panel->childGetValue("fixed_sun_check").asBoolean(); - panel->childSetEnabled("use_global_time_check", enabled); - panel->childSetValue("use_global_time_check", LLSD(FALSE)); - panel->enableButton("apply_btn"); - } -} - - - - -//--------------------------------------------------------------------------- -// Add/Remove estate access button callbacks -//--------------------------------------------------------------------------- -void LLPanelEstateInfo::onClickEditSky(void* user_data) -{ - LLFloaterWindLight::show(); -} - -void LLPanelEstateInfo::onClickEditDayCycle(void* user_data) -{ - LLFloaterDayCycle::show(); -} - -// static -void LLPanelEstateInfo::onClickAddAllowedAgent(void* user_data) -{ - LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data; - LLCtrlListInterface *list = self->childGetListInterface("allowed_avatar_name_list"); - if (!list) return; - if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) - { - //args - - LLSD args; - args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - LLNotifications::instance().add("MaxAllowedAgentOnRegion", args); - return; - } - accessAddCore(ESTATE_ACCESS_ALLOWED_AGENT_ADD, "EstateAllowedAgentAdd"); -} - -// static -void LLPanelEstateInfo::onClickRemoveAllowedAgent(void* user_data) -{ - accessRemoveCore(ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, "EstateAllowedAgentRemove", "allowed_avatar_name_list"); -} - -// static -void LLPanelEstateInfo::onClickAddAllowedGroup(void* user_data) -{ - LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data; - LLCtrlListInterface *list = self->childGetListInterface("allowed_group_name_list"); - if (!list) return; - if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) - { - LLSD args; - args["MAX_GROUPS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - LLNotifications::instance().add("MaxAllowedGroupsOnRegion", args); - return; - } - - LLNotification::Params params("ChangeLindenAccess"); - params.functor(boost::bind(&LLPanelEstateInfo::addAllowedGroup, self, _1, _2)); - if (isLindenEstate()) - { - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 0); - } -} - -bool LLPanelEstateInfo::addAllowedGroup(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option != 0) return false; - - LLFloater* parent_floater = gFloaterView->getParentFloater(this); - - LLFloaterGroupPicker* widget; - widget = LLFloaterGroupPicker::showInstance(LLSD(gAgent.getID())); - if (widget) - { - widget->setSelectCallback(addAllowedGroup2, NULL); - if (parent_floater) - { - LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, widget); - widget->setOrigin(new_rect.mLeft, new_rect.mBottom); - parent_floater->addDependentFloater(widget); - } - } - - return false; -} - -// static -void LLPanelEstateInfo::onClickRemoveAllowedGroup(void* user_data) -{ - accessRemoveCore(ESTATE_ACCESS_ALLOWED_GROUP_REMOVE, "EstateAllowedGroupRemove", "allowed_group_name_list"); -} - -// static -void LLPanelEstateInfo::onClickAddBannedAgent(void* user_data) -{ - LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data; - LLCtrlListInterface *list = self->childGetListInterface("banned_avatar_name_list"); - if (!list) return; - if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) - { - LLSD args; - args["MAX_BANNED"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - LLNotifications::instance().add("MaxBannedAgentsOnRegion", args); - return; - } - accessAddCore(ESTATE_ACCESS_BANNED_AGENT_ADD, "EstateBannedAgentAdd"); -} - -// static -void LLPanelEstateInfo::onClickRemoveBannedAgent(void* user_data) -{ - accessRemoveCore(ESTATE_ACCESS_BANNED_AGENT_REMOVE, "EstateBannedAgentRemove", "banned_avatar_name_list"); -} - -// static -void LLPanelEstateInfo::onClickAddEstateManager(void* user_data) -{ - LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data; - LLCtrlListInterface *list = self->childGetListInterface("estate_manager_name_list"); - if (!list) return; - if (list->getItemCount() >= ESTATE_MAX_MANAGERS) - { // Tell user they can't add more managers - LLSD args; - args["MAX_MANAGER"] = llformat("%d",ESTATE_MAX_MANAGERS); - LLNotifications::instance().add("MaxManagersOnRegion", args); - } - else - { // Go pick managers to add - accessAddCore(ESTATE_ACCESS_MANAGER_ADD, "EstateManagerAdd"); - } -} - -// static -void LLPanelEstateInfo::onClickRemoveEstateManager(void* user_data) -{ - accessRemoveCore(ESTATE_ACCESS_MANAGER_REMOVE, "EstateManagerRemove", "estate_manager_name_list"); -} - -//--------------------------------------------------------------------------- -// Kick from estate methods -//--------------------------------------------------------------------------- -struct LLKickFromEstateInfo -{ - LLPanelEstateInfo *mEstatePanelp; - LLUUID mAgentID; -}; - -void LLPanelEstateInfo::onClickKickUser(void *user_data) -{ - LLPanelEstateInfo* panelp = (LLPanelEstateInfo*)user_data; - - // this depends on the grandparent view being a floater - // in order to set up floater dependency - LLFloater* parent_floater = gFloaterView->getParentFloater(panelp); - LLFloater* child_floater = LLFloaterAvatarPicker::show(LLPanelEstateInfo::onKickUserCommit, user_data, FALSE, TRUE); - parent_floater->addDependentFloater(child_floater); -} - -void LLPanelEstateInfo::onKickUserCommit(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* userdata) -{ - if (names.empty() || ids.empty()) return; - - //check to make sure there is one valid user and id - if( (ids[0].isNull()) || - (names[0].length() == 0) ) - { - return; - } - - LLPanelEstateInfo* self = (LLPanelEstateInfo*)userdata; - if(!self) return; - - //keep track of what user they want to kick and other misc info - LLKickFromEstateInfo *kick_info = new LLKickFromEstateInfo(); - kick_info->mEstatePanelp = self; - kick_info->mAgentID = ids[0]; - - //Bring up a confirmation dialog - LLSD args; - args["EVIL_USER"] = names[0]; - LLSD payload; - payload["agent_id"] = ids[0]; - LLNotifications::instance().add("EstateKickUser", args, payload, boost::bind(&LLPanelEstateInfo::kickUserConfirm, self, _1, _2)); - -} - -bool LLPanelEstateInfo::kickUserConfirm(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case 0: - { - //Kick User - strings_t strings; - strings.push_back(notification["payload"]["agent_id"].asString()); - - sendEstateOwnerMessage(gMessageSystem, "kickestate", LLFloaterRegionInfo::getLastInvoice(), strings); - break; - } - default: - break; - } - return false; -} - -//--------------------------------------------------------------------------- -// Core Add/Remove estate access methods -// TODO: INTERNATIONAL: don't build message text here; -// instead, create multiple translatable messages and choose -// one based on the status. -//--------------------------------------------------------------------------- -std::string all_estates_text() -{ - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - if (!panel) return "(error)"; - - std::string owner = panel->getOwnerName(); - - LLViewerRegion* region = gAgent.getRegion(); - if (gAgent.isGodlike()) - { - return llformat("all estates\nowned by %s", owner.c_str()); - } - else if (region && region->getOwner() == gAgent.getID()) - { - return "all estates you own"; - } - else if (region && region->isEstateManager()) - { - return llformat("all estates that\nyou manage for %s", owner.c_str()); - } - else - { - return "(error)"; - } -} - -// static -bool LLPanelEstateInfo::isLindenEstate() -{ - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - if (!panel) return false; - - U32 estate_id = panel->getEstateID(); - return (estate_id <= ESTATE_LAST_LINDEN); -} - -typedef std::vector<LLUUID> AgentOrGroupIDsVector; -struct LLEstateAccessChangeInfo -{ - LLEstateAccessChangeInfo(const LLSD& sd) - { - mDialogName = sd["dialog_name"].asString(); - mOperationFlag = (U32)sd["operation"].asInteger(); - LLSD::array_const_iterator end_it = sd["allowed_ids"].endArray(); - for (LLSD::array_const_iterator id_it = sd["allowed_ids"].beginArray(); - id_it != end_it; - ++id_it) - { - mAgentOrGroupIDs.push_back(id_it->asUUID()); - } - } - - const LLSD asLLSD() const - { - LLSD sd; - sd["name"] = mDialogName; - sd["operation"] = (S32)mOperationFlag; - for (AgentOrGroupIDsVector::const_iterator it = mAgentOrGroupIDs.begin(); - it != mAgentOrGroupIDs.end(); - ++it) - { - sd["allowed_ids"].append(*it); - } - return sd; - } - - U32 mOperationFlag; // ESTATE_ACCESS_BANNED_AGENT_ADD, _REMOVE, etc. - std::string mDialogName; - AgentOrGroupIDsVector mAgentOrGroupIDs; // List of agent IDs to apply to this change -}; - -// Special case callback for groups, since it has different callback format than names -// static -void LLPanelEstateInfo::addAllowedGroup2(LLUUID id, void* user_data) -{ - LLSD payload; - payload["operation"] = (S32)ESTATE_ACCESS_ALLOWED_GROUP_ADD; - payload["dialog_name"] = "EstateAllowedGroupAdd"; - payload["allowed_ids"].append(id); - - LLSD args; - args["ALL_ESTATES"] = all_estates_text(); - - LLNotification::Params params("EstateAllowedGroupAdd"); - params.payload(payload) - .substitutions(args) - .functor(accessCoreConfirm); - if (isLindenEstate()) - { - LLNotifications::instance().forceResponse(params, 0); - } - else - { - LLNotifications::instance().add(params); - } -} - -// static -void LLPanelEstateInfo::accessAddCore(U32 operation_flag, const std::string& dialog_name) -{ - LLSD payload; - payload["operation"] = (S32)operation_flag; - payload["dialog_name"] = dialog_name; - // agent id filled in after avatar picker - - LLNotification::Params params("ChangeLindenAccess"); - params.payload(payload) - .functor(accessAddCore2); - - if (isLindenEstate()) - { - LLNotifications::instance().add(params); - } - else - { - // same as clicking "OK" - LLNotifications::instance().forceResponse(params, 0); - } -} - -// static -bool LLPanelEstateInfo::accessAddCore2(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option != 0) - { - // abort change - return false; - } - - LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo(notification["payload"]); - // avatar picker yes multi-select, yes close-on-select - LLFloaterAvatarPicker::show(accessAddCore3, (void*)change_info, TRUE, TRUE); - return false; -} - -// static -void LLPanelEstateInfo::accessAddCore3(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* data) -{ - LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data; - if (!change_info) return; - if (ids.empty()) - { - // User didn't select a name. - delete change_info; - change_info = NULL; - return; - } - // User did select a name. - change_info->mAgentOrGroupIDs = ids; - // Can't put estate owner on ban list - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - if (!panel) return; - LLViewerRegion* region = gAgent.getRegion(); - if (!region) return; - - if (change_info->mOperationFlag & ESTATE_ACCESS_ALLOWED_AGENT_ADD) - { - LLCtrlListInterface *list = panel->childGetListInterface("allowed_avatar_name_list"); - int currentCount = (list ? list->getItemCount() : 0); - if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS) - { - LLSD args; - args["NUM_ADDED"] = llformat("%d",ids.size()); - args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - args["LIST_TYPE"] = "Allowed Residents"; - args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); - LLNotifications::instance().add("MaxAgentOnRegionBatch", args); - delete change_info; - return; - } - } - if (change_info->mOperationFlag & ESTATE_ACCESS_BANNED_AGENT_ADD) - { - LLCtrlListInterface *list = panel->childGetListInterface("banned_avatar_name_list"); - int currentCount = (list ? list->getItemCount() : 0); - if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS) - { - LLSD args; - args["NUM_ADDED"] = llformat("%d",ids.size()); - args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - args["LIST_TYPE"] = "Banned Residents"; - args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); - LLNotifications::instance().add("MaxAgentOnRegionBatch", args); - delete change_info; - return; - } - } - - LLSD args; - args["ALL_ESTATES"] = all_estates_text(); - - LLNotification::Params params(change_info->mDialogName); - params.substitutions(args) - .payload(change_info->asLLSD()) - .functor(accessCoreConfirm); - - if (isLindenEstate()) - { - // just apply to this estate - LLNotifications::instance().forceResponse(params, 0); - } - else - { - // ask if this estate or all estates with this owner - LLNotifications::instance().add(params); - } -} - -// static -void LLPanelEstateInfo::accessRemoveCore(U32 operation_flag, const std::string& dialog_name, const std::string& list_ctrl_name) -{ - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - if (!panel) return; - LLNameListCtrl* name_list = panel->getChild<LLNameListCtrl>(list_ctrl_name); - if (!name_list) return; - - std::vector<LLScrollListItem*> list_vector = name_list->getAllSelected(); - if (list_vector.size() == 0) - return; - - LLSD payload; - payload["operation"] = (S32)operation_flag; - payload["dialog_name"] = dialog_name; - - for (std::vector<LLScrollListItem*>::const_iterator iter = list_vector.begin(); - iter != list_vector.end(); - iter++) - { - LLScrollListItem *item = (*iter); - payload["allowed_ids"].append(item->getUUID()); - } - - LLNotification::Params params("ChangeLindenAccess"); - params.payload(payload) - .functor(accessRemoveCore2); - - if (isLindenEstate()) - { - // warn on change linden estate - LLNotifications::instance().add(params); - } - else - { - // just proceed, as if clicking OK - LLNotifications::instance().forceResponse(params, 0); - } -} - -// static -bool LLPanelEstateInfo::accessRemoveCore2(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option != 0) - { - // abort - return false; - } - - // If Linden estate, can only apply to "this" estate, not all estates - // owned by NULL. - if (isLindenEstate()) - { - accessCoreConfirm(notification, response); - } - else - { - LLSD args; - args["ALL_ESTATES"] = all_estates_text(); - LLNotifications::instance().add(notification["payload"]["dialog_name"], - args, - notification["payload"], - accessCoreConfirm); - } - return false; -} - -// Used for both access add and remove operations, depending on the mOperationFlag -// passed in (ESTATE_ACCESS_BANNED_AGENT_ADD, ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, etc.) -// static -bool LLPanelEstateInfo::accessCoreConfirm(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - const U32 originalFlags = (U32)notification["payload"]["operation"].asInteger(); - - LLViewerRegion* region = gAgent.getRegion(); - - LLSD::array_const_iterator end_it = notification["payload"]["allowed_ids"].endArray(); - - for (LLSD::array_const_iterator iter = notification["payload"]["allowed_ids"].beginArray(); - iter != end_it; - iter++) - { - U32 flags = originalFlags; - if (iter + 1 != end_it) - flags |= ESTATE_ACCESS_NO_REPLY; - - const LLUUID id = iter->asUUID(); - if (((U32)notification["payload"]["operation"].asInteger() & ESTATE_ACCESS_BANNED_AGENT_ADD) - && region && (region->getOwner() == id)) - { - LLNotifications::instance().add("OwnerCanNotBeDenied"); - break; - } - switch(option) - { - case 0: - // This estate - sendEstateAccessDelta(flags, id); - break; - case 1: - { - // All estates, either than I own or manage for this owner. - // This will be verified on simulator. JC - if (!region) break; - if (region->getOwner() == gAgent.getID() - || gAgent.isGodlike()) - { - flags |= ESTATE_ACCESS_APPLY_TO_ALL_ESTATES; - sendEstateAccessDelta(flags, id); - } - else if (region->isEstateManager()) - { - flags |= ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES; - sendEstateAccessDelta(flags, id); - } - break; - } - case 2: - default: - break; - } - } - return false; -} - -// key = "estateaccessdelta" -// str(estate_id) will be added to front of list by forward_EstateOwnerRequest_to_dataserver -// str[0] = str(agent_id) requesting the change -// str[1] = str(flags) (ESTATE_ACCESS_DELTA_*) -// str[2] = str(agent_id) to add or remove -// static -void LLPanelEstateInfo::sendEstateAccessDelta(U32 flags, const LLUUID& agent_or_group_id) -{ - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("EstateOwnerMessage"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used - - msg->nextBlock("MethodData"); - msg->addString("Method", "estateaccessdelta"); - msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice()); - - std::string buf; - gAgent.getID().toString(buf); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buf); - - buf = llformat("%u", flags); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buf); - - agent_or_group_id.toString(buf); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buf); - - - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - - if (flags & (ESTATE_ACCESS_ALLOWED_AGENT_ADD | ESTATE_ACCESS_ALLOWED_AGENT_REMOVE | - ESTATE_ACCESS_BANNED_AGENT_ADD | ESTATE_ACCESS_BANNED_AGENT_REMOVE)) - { - - panel->clearAccessLists(); - } - - gAgent.sendReliableMessage(); -} - -void LLPanelEstateInfo::updateControls(LLViewerRegion* region) -{ - BOOL god = gAgent.isGodlike(); - BOOL owner = (region && (region->getOwner() == gAgent.getID())); - BOOL manager = (region && region->isEstateManager()); - setCtrlsEnabled(god || owner || manager); - - childDisable("apply_btn"); - childSetEnabled("add_allowed_avatar_btn", god || owner || manager); - childSetEnabled("remove_allowed_avatar_btn", god || owner || manager); - childSetEnabled("add_allowed_group_btn", god || owner || manager); - childSetEnabled("remove_allowed_group_btn", god || owner || manager); - childSetEnabled("add_banned_avatar_btn", god || owner || manager); - childSetEnabled("remove_banned_avatar_btn", god || owner || manager); - childSetEnabled("message_estate_btn", god || owner || manager); - childSetEnabled("kick_user_from_estate_btn", god || owner || manager); -#if ELAR_ENABLED - childSetEnabled("abuse_email_address", god || owner || manager); -#else - childSetEnabled("abuse_email_address", false); -#endif - - // estate managers can't add estate managers - childSetEnabled("add_estate_manager_btn", god || owner); - childSetEnabled("remove_estate_manager_btn", god || owner); - childSetEnabled("estate_manager_name_list", god || owner); -} - -bool LLPanelEstateInfo::refreshFromRegion(LLViewerRegion* region) -{ - updateControls(region); - - // let the parent class handle the general data collection. - bool rv = LLPanelRegionInfo::refreshFromRegion(region); - - // We want estate info. To make sure it works across region - // boundaries and multiple packets, we add a serial number to the - // integers and track against that on update. - strings_t strings; - //integers_t integers; - //LLFloaterRegionInfo::incrementSerial(); - LLFloaterRegionInfo::nextInvoice(); - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - //integers.push_back(LLFloaterRegionInfo::());::getPanelEstate(); - - - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - panel->clearAccessLists(); - - - sendEstateOwnerMessage(gMessageSystem, "getinfo", invoice, strings); - - refresh(); - - return rv; -} - -void LLPanelEstateInfo::updateChild(LLUICtrl* child_ctrl) -{ - if (checkRemovalButton(child_ctrl->getName())) - { - // do nothing - } - else if (checkSunHourSlider(child_ctrl)) - { - // do nothing - } -} - -bool LLPanelEstateInfo::estateUpdate(LLMessageSystem* msg) -{ - llinfos << "LLPanelEstateInfo::estateUpdate()" << llendl; - return false; -} - - -BOOL LLPanelEstateInfo::postBuild() -{ - // set up the callbacks for the generic controls - initCtrl("externally_visible_check"); - initCtrl("use_global_time_check"); - initCtrl("fixed_sun_check"); - initCtrl("allow_direct_teleport"); - initCtrl("limit_payment"); - initCtrl("limit_age_verified"); - initCtrl("voice_chat_check"); - childSetCommitCallback("abuse_email_address", onChangeAnything, this); - childSetKeystrokeCallback("abuse_email_address", onChangeText, this); - - initHelpBtn("estate_manager_help", "HelpEstateEstateManager"); - initHelpBtn("use_global_time_help", "HelpEstateUseGlobalTime"); - initHelpBtn("fixed_sun_help", "HelpEstateFixedSun"); - initHelpBtn("WLEditSkyHelp", "HelpEditSky"); - initHelpBtn("WLEditDayCycleHelp", "HelpEditDayCycle"); - - initHelpBtn("externally_visible_help", "HelpEstateExternallyVisible"); - initHelpBtn("allow_direct_teleport_help", "HelpEstateAllowDirectTeleport"); - initHelpBtn("allow_resident_help", "HelpEstateAllowResident"); - initHelpBtn("allow_group_help", "HelpEstateAllowGroup"); - initHelpBtn("ban_resident_help", "HelpEstateBanResident"); - initHelpBtn("abuse_email_address_help", "HelpEstateAbuseEmailAddress"); - initHelpBtn("voice_chat_help", "HelpEstateVoiceChat"); - - // set up the use global time checkbox - childSetCommitCallback("use_global_time_check", onChangeUseGlobalTime, this); - childSetCommitCallback("fixed_sun_check", onChangeFixedSun, this); - childSetCommitCallback("sun_hour_slider", onChangeChildCtrl, this); - - childSetCommitCallback("allowed_avatar_name_list", onChangeChildCtrl, this); - LLNameListCtrl *avatar_name_list = getChild<LLNameListCtrl>("allowed_avatar_name_list"); - if (avatar_name_list) - { - avatar_name_list->setCommitOnSelectionChange(TRUE); - avatar_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); - } - - childSetAction("add_allowed_avatar_btn", onClickAddAllowedAgent, this); - childSetAction("remove_allowed_avatar_btn", onClickRemoveAllowedAgent, this); - - childSetCommitCallback("allowed_group_name_list", onChangeChildCtrl, this); - LLNameListCtrl* group_name_list = getChild<LLNameListCtrl>("allowed_group_name_list"); - if (group_name_list) - { - group_name_list->setCommitOnSelectionChange(TRUE); - group_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); - } - - childSetAction("add_allowed_group_btn", onClickAddAllowedGroup, this); - childSetAction("remove_allowed_group_btn", onClickRemoveAllowedGroup, this); - - childSetCommitCallback("banned_avatar_name_list", onChangeChildCtrl, this); - LLNameListCtrl* banned_name_list = getChild<LLNameListCtrl>("banned_avatar_name_list"); - if (banned_name_list) - { - banned_name_list->setCommitOnSelectionChange(TRUE); - banned_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); - } - - childSetAction("add_banned_avatar_btn", onClickAddBannedAgent, this); - childSetAction("remove_banned_avatar_btn", onClickRemoveBannedAgent, this); - - childSetCommitCallback("estate_manager_name_list", onChangeChildCtrl, this); - LLNameListCtrl* manager_name_list = getChild<LLNameListCtrl>("estate_manager_name_list"); - if (manager_name_list) - { - manager_name_list->setCommitOnSelectionChange(TRUE); - manager_name_list->setMaxItemCount(ESTATE_MAX_MANAGERS * 4); // Allow extras for dupe issue - } - - childSetAction("add_estate_manager_btn", onClickAddEstateManager, this); - childSetAction("remove_estate_manager_btn", onClickRemoveEstateManager, this); - childSetAction("message_estate_btn", onClickMessageEstate, this); - childSetAction("kick_user_from_estate_btn", onClickKickUser, this); - - childSetAction("WLEditSky", onClickEditSky, this); - childSetAction("WLEditDayCycle", onClickEditDayCycle, this); - - return LLPanelRegionInfo::postBuild(); -} - -void LLPanelEstateInfo::refresh() -{ - bool public_access = childGetValue("externally_visible_check").asBoolean(); - childSetEnabled("Only Allow", public_access); - childSetEnabled("limit_payment", public_access); - childSetEnabled("limit_age_verified", public_access); - // if this is set to false, then the limit fields are meaningless and should be turned off - if (public_access == false) - { - childSetValue("limit_payment", false); - childSetValue("limit_age_verified", false); - } -} - -BOOL LLPanelEstateInfo::sendUpdate() -{ - llinfos << "LLPanelEsateInfo::sendUpdate()" << llendl; - - LLNotification::Params params("ChangeLindenEstate"); - params.functor(boost::bind(&LLPanelEstateInfo::callbackChangeLindenEstate, this, _1, _2)); - - if (getEstateID() <= ESTATE_LAST_LINDEN) - { - // trying to change reserved estate, warn - LLNotifications::instance().add(params); - } - else - { - // for normal estates, just make the change - LLNotifications::instance().forceResponse(params, 0); - } - return TRUE; -} - -bool LLPanelEstateInfo::callbackChangeLindenEstate(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case 0: - // send the update - if (!commitEstateInfoCaps()) - { - // the caps method failed, try the old way - LLFloaterRegionInfo::nextInvoice(); - commitEstateInfoDataserver(); - } - // we don't want to do this because we'll get it automatically from the sim - // after the spaceserver processes it -// else -// { -// // caps method does not automatically send this info -// LLFloaterRegionInfo::requestRegionInfo(); -// } - break; - case 1: - default: - // do nothing - break; - } - return false; -} - - -/* -// Request = "getowner" -// SParam[0] = "" (empty string) -// IParam[0] = serial -void LLPanelEstateInfo::getEstateOwner() -{ - // TODO -- disable the panel - // and call this function whenever we cross a region boundary - // re-enable when owner matches, and get new estate info - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_EstateOwnerRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - - msg->nextBlockFast(_PREHASH_RequestData); - msg->addStringFast(_PREHASH_Request, "getowner"); - - // we send an empty string so that the variable block is not empty - msg->nextBlockFast(_PREHASH_StringData); - msg->addStringFast(_PREHASH_SParam, ""); - - msg->nextBlockFast(_PREHASH_IntegerData); - msg->addS32Fast(_PREHASH_IParam, LLFloaterRegionInfo::getSerial()); - - gAgent.sendMessage(); -} -*/ - -class LLEstateChangeInfoResponder : public LLHTTPClient::Responder -{ -public: - LLEstateChangeInfoResponder(void* userdata) : mpPanel((LLPanelEstateInfo*)userdata) {}; - - // if we get a normal response, handle it here - virtual void result(const LLSD& content) - { - // refresh the panel from the database - mpPanel->refresh(); - } - - // if we get an error response - virtual void error(U32 status, const std::string& reason) - { - llinfos << "LLEstateChangeInfoResponder::error " - << status << ": " << reason << llendl; - } -private: - LLPanelEstateInfo* mpPanel; -}; - -// tries to send estate info using a cap; returns true if it succeeded -bool LLPanelEstateInfo::commitEstateInfoCaps() -{ - std::string url = gAgent.getRegion()->getCapability("EstateChangeInfo"); - - if (url.empty()) - { - // whoops, couldn't find the cap, so bail out - return false; - } - - LLSD body; - body["estate_name"] = getEstateName(); - - body["is_externally_visible"] = childGetValue("externally_visible_check").asBoolean(); - body["allow_direct_teleport"] = childGetValue("allow_direct_teleport").asBoolean(); - body["is_sun_fixed" ] = childGetValue("fixed_sun_check").asBoolean(); - body["deny_anonymous" ] = childGetValue("limit_payment").asBoolean(); - body["deny_age_unverified" ] = childGetValue("limit_age_verified").asBoolean(); - body["allow_voice_chat" ] = childGetValue("voice_chat_check").asBoolean(); - body["invoice" ] = LLFloaterRegionInfo::getLastInvoice(); - - // block fly is in estate database but not in estate UI, so we're not supporting it - //body["block_fly" ] = childGetValue("").asBoolean(); - - F32 sun_hour = getSunHour(); - if (childGetValue("use_global_time_check").asBoolean()) - { - sun_hour = 0.f; // 0 = global time - } - body["sun_hour"] = sun_hour; - - body["owner_abuse_email"] = childGetValue("abuse_email_address").asString(); - - // we use a responder so that we can re-get the data after committing to the database - LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder((void*)this)); - return true; -} - -/* This is the old way of doing things, is deprecated, and should be - deleted when the dataserver model can be removed */ -// key = "estatechangeinfo" -// strings[0] = str(estate_id) (added by simulator before relay - not here) -// strings[1] = estate_name -// strings[2] = str(estate_flags) -// strings[3] = str((S32)(sun_hour * 1024.f)) -void LLPanelEstateInfo::commitEstateInfoDataserver() -{ - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("EstateOwnerMessage"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used - - msg->nextBlock("MethodData"); - msg->addString("Method", "estatechangeinfo"); - msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice()); - - msg->nextBlock("ParamList"); - msg->addString("Parameter", getEstateName()); - - std::string buffer; - buffer = llformat("%u", computeEstateFlags()); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - - F32 sun_hour = getSunHour(); - if (childGetValue("use_global_time_check").asBoolean()) - { - sun_hour = 0.f; // 0 = global time - } - - buffer = llformat("%d", (S32)(sun_hour*1024.0f)); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - - gAgent.sendMessage(); -} - -void LLPanelEstateInfo::setEstateFlags(U32 flags) -{ - childSetValue("externally_visible_check", LLSD(flags & REGION_FLAGS_EXTERNALLY_VISIBLE ? TRUE : FALSE) ); - childSetValue("fixed_sun_check", LLSD(flags & REGION_FLAGS_SUN_FIXED ? TRUE : FALSE) ); - childSetValue( - "voice_chat_check", - LLSD(flags & REGION_FLAGS_ALLOW_VOICE ? TRUE : FALSE)); - childSetValue("allow_direct_teleport", LLSD(flags & REGION_FLAGS_ALLOW_DIRECT_TELEPORT ? TRUE : FALSE) ); - childSetValue("limit_payment", LLSD(flags & REGION_FLAGS_DENY_ANONYMOUS ? TRUE : FALSE) ); - childSetValue("limit_age_verified", LLSD(flags & REGION_FLAGS_DENY_AGEUNVERIFIED ? TRUE : FALSE) ); - - refresh(); -} - -U32 LLPanelEstateInfo::computeEstateFlags() -{ - U32 flags = 0; - - if (childGetValue("externally_visible_check").asBoolean()) - { - flags |= REGION_FLAGS_EXTERNALLY_VISIBLE; - } - - if ( childGetValue("voice_chat_check").asBoolean() ) - { - flags |= REGION_FLAGS_ALLOW_VOICE; - } - - if (childGetValue("allow_direct_teleport").asBoolean()) - { - flags |= REGION_FLAGS_ALLOW_DIRECT_TELEPORT; - } - - if (childGetValue("fixed_sun_check").asBoolean()) - { - flags |= REGION_FLAGS_SUN_FIXED; - } - - if (childGetValue("limit_payment").asBoolean()) - { - flags |= REGION_FLAGS_DENY_ANONYMOUS; - } - - if (childGetValue("limit_age_verified").asBoolean()) - { - flags |= REGION_FLAGS_DENY_AGEUNVERIFIED; - } - - - return flags; -} - -BOOL LLPanelEstateInfo::getGlobalTime() -{ - return childGetValue("use_global_time_check").asBoolean(); -} - -void LLPanelEstateInfo::setGlobalTime(bool b) -{ - childSetValue("use_global_time_check", LLSD(b)); - childSetEnabled("fixed_sun_check", LLSD(!b)); - childSetEnabled("sun_hour_slider", LLSD(!b)); - if (b) - { - childSetValue("sun_hour_slider", LLSD(0.f)); - } -} - - -BOOL LLPanelEstateInfo::getFixedSun() -{ - return childGetValue("fixed_sun_check").asBoolean(); -} - -void LLPanelEstateInfo::setSunHour(F32 sun_hour) -{ - if(sun_hour < 6.0f) - { - sun_hour = 24.0f + sun_hour; - } - childSetValue("sun_hour_slider", LLSD(sun_hour)); -} - -F32 LLPanelEstateInfo::getSunHour() -{ - if (childIsEnabled("sun_hour_slider")) - { - return (F32)childGetValue("sun_hour_slider").asReal(); - } - return 0.f; -} - -const std::string LLPanelEstateInfo::getEstateName() const -{ - return childGetValue("estate_name").asString(); -} - -void LLPanelEstateInfo::setEstateName(const std::string& name) -{ - childSetValue("estate_name", LLSD(name)); -} - -const std::string LLPanelEstateInfo::getOwnerName() const -{ - return childGetValue("estate_owner").asString(); -} - -void LLPanelEstateInfo::setOwnerName(const std::string& name) -{ - childSetValue("estate_owner", LLSD(name)); -} - -const std::string LLPanelEstateInfo::getAbuseEmailAddress() const -{ - return childGetValue("abuse_email_address").asString(); -} - -void LLPanelEstateInfo::setAbuseEmailAddress(const std::string& address) -{ - childSetValue("abuse_email_address", LLSD(address)); -} - -void LLPanelEstateInfo::setAccessAllowedEnabled(bool enable_agent, - bool enable_group, - bool enable_ban) -{ - childSetEnabled("allow_resident_label", enable_agent); - childSetEnabled("allowed_avatar_name_list", enable_agent); - childSetVisible("allowed_avatar_name_list", enable_agent); - childSetEnabled("add_allowed_avatar_btn", enable_agent); - childSetEnabled("remove_allowed_avatar_btn", enable_agent); - - // Groups - childSetEnabled("allow_group_label", enable_group); - childSetEnabled("allowed_group_name_list", enable_group); - childSetVisible("allowed_group_name_list", enable_group); - childSetEnabled("add_allowed_group_btn", enable_group); - childSetEnabled("remove_allowed_group_btn", enable_group); - - // Ban - childSetEnabled("ban_resident_label", enable_ban); - childSetEnabled("banned_avatar_name_list", enable_ban); - childSetVisible("banned_avatar_name_list", enable_ban); - childSetEnabled("add_banned_avatar_btn", enable_ban); - childSetEnabled("remove_banned_avatar_btn", enable_ban); - - // Update removal buttons if needed - if (enable_agent) - { - checkRemovalButton("allowed_avatar_name_list"); - } - - if (enable_group) - { - checkRemovalButton("allowed_group_name_list"); - } - - if (enable_ban) - { - checkRemovalButton("banned_avatar_name_list"); - } -} - -// static -void LLPanelEstateInfo::callbackCacheName( - const LLUUID& id, - const std::string& first, - const std::string& last, - BOOL is_group, - void*) -{ - LLPanelEstateInfo* self = LLFloaterRegionInfo::getPanelEstate(); - if (!self) return; - - std::string name; - - if (id.isNull()) - { - name = "(none)"; - } - else - { - name = first + " " + last; - } - - self->setOwnerName(name); -} - -void LLPanelEstateInfo::clearAccessLists() -{ - LLNameListCtrl* name_list = getChild<LLNameListCtrl>("allowed_avatar_name_list"); - if (name_list) - { - name_list->deleteAllItems(); - } - - name_list = getChild<LLNameListCtrl>("banned_avatar_name_list"); - if (name_list) - { - name_list->deleteAllItems(); - } -} - -// enables/disables the "remove" button for the various allow/ban lists -BOOL LLPanelEstateInfo::checkRemovalButton(std::string name) -{ - std::string btn_name = ""; - if (name == "allowed_avatar_name_list") - { - btn_name = "remove_allowed_avatar_btn"; - } - else if (name == "allowed_group_name_list") - { - btn_name = "remove_allowed_group_btn"; - } - else if (name == "banned_avatar_name_list") - { - btn_name = "remove_banned_avatar_btn"; - } - else if (name == "estate_manager_name_list") - { - //ONLY OWNER CAN ADD /DELET ESTATE MANAGER - LLViewerRegion* region = gAgent.getRegion(); - if (region && (region->getOwner() == gAgent.getID())) - { - btn_name = "remove_estate_manager_btn"; - } - } - - // enable the remove button if something is selected - LLNameListCtrl* name_list = getChild<LLNameListCtrl>(name); - childSetEnabled(btn_name, name_list && name_list->getFirstSelected() ? TRUE : FALSE); - - return (btn_name != ""); -} - -BOOL LLPanelEstateInfo::checkSunHourSlider(LLUICtrl* child_ctrl) -{ - BOOL found_child_ctrl = FALSE; - if (child_ctrl->getName() == "sun_hour_slider") - { - enableButton("apply_btn"); - found_child_ctrl = TRUE; - } - return found_child_ctrl; -} - -// static -void LLPanelEstateInfo::onClickMessageEstate(void* userdata) -{ - llinfos << "LLPanelEstateInfo::onClickMessageEstate" << llendl; - LLNotifications::instance().add("MessageEstate", LLSD(), LLSD(), boost::bind(&LLPanelEstateInfo::onMessageCommit, (LLPanelEstateInfo*)userdata, _1, _2)); -} - -bool LLPanelEstateInfo::onMessageCommit(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - std::string text = response["message"].asString(); - if(option != 0) return false; - if(text.empty()) return false; - llinfos << "Message to everyone: " << text << llendl; - strings_t strings; - //integers_t integers; - std::string name; - gAgent.buildFullname(name); - strings.push_back(strings_t::value_type(name)); - strings.push_back(strings_t::value_type(text)); - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - sendEstateOwnerMessage(gMessageSystem, "instantmessage", invoice, strings); - return false; -} - -LLPanelEstateCovenant::LLPanelEstateCovenant() -: mCovenantID(LLUUID::null) -{ -} - -// virtual -bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region) -{ - LLTextBox* region_name = getChild<LLTextBox>("region_name_text"); - if (region_name) - { - region_name->setText(region->getName()); - } - - LLTextBox* resellable_clause = getChild<LLTextBox>("resellable_clause"); - if (resellable_clause) - { - if (region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL) - { - resellable_clause->setText(getString("can_not_resell")); - } - else - { - resellable_clause->setText(getString("can_resell")); - } - } - - LLTextBox* changeable_clause = getChild<LLTextBox>("changeable_clause"); - if (changeable_clause) - { - if (region->getRegionFlags() & REGION_FLAGS_ALLOW_PARCEL_CHANGES) - { - changeable_clause->setText(getString("can_change")); - } - else - { - changeable_clause->setText(getString("can_not_change")); - } - } - - LLTextBox* region_maturity = getChild<LLTextBox>("region_maturity_text"); - if (region_maturity) - { - region_maturity->setText(region->getSimAccessString()); - } - - LLTextBox* region_landtype = getChild<LLTextBox>("region_landtype_text"); - if (region_landtype) - { - region_landtype->setText(region->getSimProductName()); - } - - - // let the parent class handle the general data collection. - bool rv = LLPanelRegionInfo::refreshFromRegion(region); - LLMessageSystem *msg = gMessageSystem; - msg->newMessage("EstateCovenantRequest"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); - msg->sendReliable(region->getHost()); - return rv; -} - -// virtual -bool LLPanelEstateCovenant::estateUpdate(LLMessageSystem* msg) -{ - llinfos << "LLPanelEstateCovenant::estateUpdate()" << llendl; - return true; -} - -// virtual -BOOL LLPanelEstateCovenant::postBuild() -{ - initHelpBtn("covenant_help", "HelpEstateCovenant"); - mEstateNameText = getChild<LLTextBox>("estate_name_text"); - mEstateOwnerText = getChild<LLTextBox>("estate_owner_text"); - mLastModifiedText = getChild<LLTextBox>("covenant_timestamp_text"); - mEditor = getChild<LLViewerTextEditor>("covenant_editor"); - if (mEditor) mEditor->setHandleEditKeysDirectly(TRUE); - LLButton* reset_button = getChild<LLButton>("reset_covenant"); - reset_button->setEnabled(gAgent.canManageEstate()); - reset_button->setClickedCallback(LLPanelEstateCovenant::resetCovenantID, NULL); - - return LLPanelRegionInfo::postBuild(); -} - -// virtual -void LLPanelEstateCovenant::updateChild(LLUICtrl* child_ctrl) -{ -} - -// virtual -BOOL LLPanelEstateCovenant::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - LLInventoryItem* item = (LLInventoryItem*)cargo_data; - - if (!gAgent.canManageEstate()) - { - *accept = ACCEPT_NO; - return TRUE; - } - - switch(cargo_type) - { - case DAD_NOTECARD: - *accept = ACCEPT_YES_COPY_SINGLE; - if (item && drop) - { - LLSD payload; - payload["item_id"] = item->getUUID(); - LLNotifications::instance().add("EstateChangeCovenant", LLSD(), payload, - LLPanelEstateCovenant::confirmChangeCovenantCallback); - } - break; - default: - *accept = ACCEPT_NO; - break; - } - - return TRUE; -} - -// static -bool LLPanelEstateCovenant::confirmChangeCovenantCallback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - LLInventoryItem* item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); - LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant(); - - if (!item || !self) return false; - - switch(option) - { - case 0: - self->loadInvItem(item); - break; - default: - break; - } - return false; -} - -// static -void LLPanelEstateCovenant::resetCovenantID(void* userdata) -{ - LLNotifications::instance().add("EstateChangeCovenant", LLSD(), LLSD(), confirmResetCovenantCallback); -} - -// static -bool LLPanelEstateCovenant::confirmResetCovenantCallback(const LLSD& notification, const LLSD& response) -{ - LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant(); - if (!self) return false; - - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case 0: - self->loadInvItem(NULL); - break; - default: - break; - } - return false; -} - -void LLPanelEstateCovenant::loadInvItem(LLInventoryItem *itemp) -{ - const BOOL high_priority = TRUE; - if (itemp) - { - gAssetStorage->getInvItemAsset(gAgent.getRegionHost(), - gAgent.getID(), - gAgent.getSessionID(), - itemp->getPermissions().getOwner(), - LLUUID::null, - itemp->getUUID(), - itemp->getAssetUUID(), - itemp->getType(), - onLoadComplete, - (void*)this, - high_priority); - mAssetStatus = ASSET_LOADING; - } - else - { - mAssetStatus = ASSET_LOADED; - setCovenantTextEditor("There is no Covenant provided for this Estate."); - sendChangeCovenantID(LLUUID::null); - } -} - -// static -void LLPanelEstateCovenant::onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) -{ - llinfos << "LLPanelEstateCovenant::onLoadComplete()" << llendl; - LLPanelEstateCovenant* panelp = (LLPanelEstateCovenant*)user_data; - if( panelp ) - { - if(0 == status) - { - LLVFile file(vfs, asset_uuid, type, LLVFile::READ); - - S32 file_length = file.getSize(); - - char* buffer = new char[file_length+1]; - if (buffer == NULL) - { - llerrs << "Memory Allocation Failed" << llendl; - return; - } - - file.read((U8*)buffer, file_length); /* Flawfinder: ignore */ - // put a EOS at the end - buffer[file_length] = 0; - - if( (file_length > 19) && !strncmp( buffer, "Linden text version", 19 ) ) - { - if( !panelp->mEditor->importBuffer( buffer, file_length+1 ) ) - { - llwarns << "Problem importing estate covenant." << llendl; - LLNotifications::instance().add("ProblemImportingEstateCovenant"); - } - else - { - panelp->sendChangeCovenantID(asset_uuid); - } - } - else - { - // Version 0 (just text, doesn't include version number) - panelp->sendChangeCovenantID(asset_uuid); - } - delete[] buffer; - } - else - { - LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED ); - - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || - LL_ERR_FILE_EMPTY == status) - { - LLNotifications::instance().add("MissingNotecardAssetID"); - } - else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) - { - LLNotifications::instance().add("NotAllowedToViewNotecard"); - } - else - { - LLNotifications::instance().add("UnableToLoadNotecardAsset"); - } - - llwarns << "Problem loading notecard: " << status << llendl; - } - panelp->mAssetStatus = ASSET_LOADED; - panelp->setCovenantID(asset_uuid); - } -} - -// key = "estatechangecovenantid" -// strings[0] = str(estate_id) (added by simulator before relay - not here) -// strings[1] = str(covenant_id) -void LLPanelEstateCovenant::sendChangeCovenantID(const LLUUID &asset_id) -{ - if (asset_id != getCovenantID()) - { - setCovenantID(asset_id); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("EstateOwnerMessage"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used - - msg->nextBlock("MethodData"); - msg->addString("Method", "estatechangecovenantid"); - msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice()); - - msg->nextBlock("ParamList"); - msg->addString("Parameter", getCovenantID().asString()); - gAgent.sendReliableMessage(); - } -} - -// virtual -BOOL LLPanelEstateCovenant::sendUpdate() -{ - return TRUE; -} - -const std::string& LLPanelEstateCovenant::getEstateName() const -{ - return mEstateNameText->getText(); -} - -void LLPanelEstateCovenant::setEstateName(const std::string& name) -{ - mEstateNameText->setText(name); -} - -// static -void LLPanelEstateCovenant::updateCovenantText(const std::string& string, const LLUUID& asset_id) -{ - LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); - if( panelp ) - { - panelp->mEditor->setText(string); - panelp->setCovenantID(asset_id); - } -} - -// static -void LLPanelEstateCovenant::updateEstateName(const std::string& name) -{ - LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); - if( panelp ) - { - panelp->mEstateNameText->setText(name); - } -} - -// static -void LLPanelEstateCovenant::updateLastModified(const std::string& text) -{ - LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); - if( panelp ) - { - panelp->mLastModifiedText->setText(text); - } -} - -// static -void LLPanelEstateCovenant::updateEstateOwnerName(const std::string& name) -{ - LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); - if( panelp ) - { - panelp->mEstateOwnerText->setText(name); - } -} - -const std::string& LLPanelEstateCovenant::getOwnerName() const -{ - return mEstateOwnerText->getText(); -} - -void LLPanelEstateCovenant::setOwnerName(const std::string& name) -{ - mEstateOwnerText->setText(name); -} - -void LLPanelEstateCovenant::setCovenantTextEditor(const std::string& text) -{ - mEditor->setText(text); -} - -// key = "estateupdateinfo" -// strings[0] = estate name -// strings[1] = str(owner_id) -// strings[2] = str(estate_id) -// strings[3] = str(estate_flags) -// strings[4] = str((S32)(sun_hour * 1024)) -// strings[5] = str(parent_estate_id) -// strings[6] = str(covenant_id) -// strings[7] = str(covenant_timestamp) -// strings[8] = str(send_to_agent_only) -// strings[9] = str(abuse_email_addr) -bool LLDispatchEstateUpdateInfo::operator()( - const LLDispatcher* dispatcher, - const std::string& key, - const LLUUID& invoice, - const sparam_t& strings) -{ - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - if (!panel) return true; - - // NOTE: LLDispatcher extracts strings with an extra \0 at the - // end. If we pass the std::string direct to the UI/renderer - // it draws with a weird character at the end of the string. - std::string estate_name = strings[0].c_str(); // preserve c_str() call! - panel->setEstateName(estate_name); - -#if ELAR_ENABLED - if (strings.size() > 9) - { - std::string abuse_email = strings[9].c_str(); // preserve c_str() call! - panel->setAbuseEmailAddress(abuse_email); - } - else -#endif - { - panel->setAbuseEmailAddress(panel->getString("email_unsupported")); - } - - LLViewerRegion* regionp = gAgent.getRegion(); - - LLUUID owner_id(strings[1]); - regionp->setOwner(owner_id); - // Update estate owner name in UI - const BOOL is_group = FALSE; - gCacheName->get(owner_id, is_group, LLPanelEstateInfo::callbackCacheName); - - U32 estate_id = strtoul(strings[2].c_str(), NULL, 10); - panel->setEstateID(estate_id); - - U32 flags = strtoul(strings[3].c_str(), NULL, 10); - panel->setEstateFlags(flags); - - F32 sun_hour = ((F32)(strtod(strings[4].c_str(), NULL)))/1024.0f; - if(sun_hour == 0 && (flags & REGION_FLAGS_SUN_FIXED ? FALSE : TRUE)) - { - panel->setGlobalTime(TRUE); - } - else - { - panel->setGlobalTime(FALSE); - panel->setSunHour(sun_hour); - } - - bool visible_from_mainland = (bool)(flags & REGION_FLAGS_EXTERNALLY_VISIBLE); - bool god = gAgent.isGodlike(); - bool linden_estate = (estate_id <= ESTATE_LAST_LINDEN); - - // If visible from mainland, disable the access allowed - // UI, as anyone can teleport there. - // However, gods need to be able to edit the access list for - // linden estates, regardless of visibility, to allow object - // and L$ transfers. - bool enable_agent = (!visible_from_mainland || (god && linden_estate)); - bool enable_group = enable_agent; - bool enable_ban = !linden_estate; - panel->setAccessAllowedEnabled(enable_agent, enable_group, enable_ban); - - return true; -} - - -// key = "setaccess" -// strings[0] = str(estate_id) -// strings[1] = str(packed_access_lists) -// strings[2] = str(num allowed agent ids) -// strings[3] = str(num allowed group ids) -// strings[4] = str(num banned agent ids) -// strings[5] = str(num estate manager agent ids) -// strings[6] = bin(uuid) -// strings[7] = bin(uuid) -// strings[8] = bin(uuid) -// ... -bool LLDispatchSetEstateAccess::operator()( - const LLDispatcher* dispatcher, - const std::string& key, - const LLUUID& invoice, - const sparam_t& strings) -{ - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - if (!panel) return true; - - S32 index = 1; // skip estate_id - U32 access_flags = strtoul(strings[index++].c_str(), NULL,10); - S32 num_allowed_agents = strtol(strings[index++].c_str(), NULL, 10); - S32 num_allowed_groups = strtol(strings[index++].c_str(), NULL, 10); - S32 num_banned_agents = strtol(strings[index++].c_str(), NULL, 10); - S32 num_estate_managers = strtol(strings[index++].c_str(), NULL, 10); - - // sanity ckecks - if (num_allowed_agents > 0 - && !(access_flags & ESTATE_ACCESS_ALLOWED_AGENTS)) - { - llwarns << "non-zero count for allowed agents, but no corresponding flag" << llendl; - } - if (num_allowed_groups > 0 - && !(access_flags & ESTATE_ACCESS_ALLOWED_GROUPS)) - { - llwarns << "non-zero count for allowed groups, but no corresponding flag" << llendl; - } - if (num_banned_agents > 0 - && !(access_flags & ESTATE_ACCESS_BANNED_AGENTS)) - { - llwarns << "non-zero count for banned agents, but no corresponding flag" << llendl; - } - if (num_estate_managers > 0 - && !(access_flags & ESTATE_ACCESS_MANAGERS)) - { - llwarns << "non-zero count for managers, but no corresponding flag" << llendl; - } - - // grab the UUID's out of the string fields - if (access_flags & ESTATE_ACCESS_ALLOWED_AGENTS) - { - LLNameListCtrl* allowed_agent_name_list; - allowed_agent_name_list = panel->getChild<LLNameListCtrl>("allowed_avatar_name_list"); - - int totalAllowedAgents = num_allowed_agents; - - if (allowed_agent_name_list) - { - totalAllowedAgents += allowed_agent_name_list->getItemCount(); - } - - std::string msg = llformat("Allowed residents: (%d, max %d)", - totalAllowedAgents, - ESTATE_MAX_ACCESS_IDS); - panel->childSetValue("allow_resident_label", LLSD(msg)); - - if (allowed_agent_name_list) - { - //allowed_agent_name_list->deleteAllItems(); - for (S32 i = 0; i < num_allowed_agents && i < ESTATE_MAX_ACCESS_IDS; i++) - { - LLUUID id; - memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ - allowed_agent_name_list->addNameItem(id); - } - panel->childSetEnabled("remove_allowed_avatar_btn", allowed_agent_name_list->getFirstSelected() ? TRUE : FALSE); - allowed_agent_name_list->sortByColumnIndex(0, TRUE); - } - } - - if (access_flags & ESTATE_ACCESS_ALLOWED_GROUPS) - { - LLNameListCtrl* allowed_group_name_list; - allowed_group_name_list = panel->getChild<LLNameListCtrl>("allowed_group_name_list"); - - std::string msg = llformat("Allowed groups: (%d, max %d)", - num_allowed_groups, - (S32) ESTATE_MAX_GROUP_IDS); - panel->childSetValue("allow_group_label", LLSD(msg)); - - if (allowed_group_name_list) - { - allowed_group_name_list->deleteAllItems(); - for (S32 i = 0; i < num_allowed_groups && i < ESTATE_MAX_GROUP_IDS; i++) - { - LLUUID id; - memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ - allowed_group_name_list->addGroupNameItem(id); - } - panel->childSetEnabled("remove_allowed_group_btn", allowed_group_name_list->getFirstSelected() ? TRUE : FALSE); - allowed_group_name_list->sortByColumnIndex(0, TRUE); - } - } - - if (access_flags & ESTATE_ACCESS_BANNED_AGENTS) - { - LLNameListCtrl* banned_agent_name_list; - banned_agent_name_list = panel->getChild<LLNameListCtrl>("banned_avatar_name_list"); - - int totalBannedAgents = num_banned_agents; - - if (banned_agent_name_list) - { - totalBannedAgents += banned_agent_name_list->getItemCount(); - } - - - std::string msg = llformat("Banned residents: (%d, max %d)", - totalBannedAgents, - ESTATE_MAX_ACCESS_IDS); - panel->childSetValue("ban_resident_label", LLSD(msg)); - - if (banned_agent_name_list) - { - //banned_agent_name_list->deleteAllItems(); - for (S32 i = 0; i < num_banned_agents && i < ESTATE_MAX_ACCESS_IDS; i++) - { - LLUUID id; - memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ - banned_agent_name_list->addNameItem(id); - } - panel->childSetEnabled("remove_banned_avatar_btn", banned_agent_name_list->getFirstSelected() ? TRUE : FALSE); - banned_agent_name_list->sortByColumnIndex(0, TRUE); - } - } - - if (access_flags & ESTATE_ACCESS_MANAGERS) - { - std::string msg = llformat("Estate Managers: (%d, max %d)", - num_estate_managers, - ESTATE_MAX_MANAGERS); - panel->childSetValue("estate_manager_label", LLSD(msg)); - - LLNameListCtrl* estate_manager_name_list = - panel->getChild<LLNameListCtrl>("estate_manager_name_list"); - if (estate_manager_name_list) - { - estate_manager_name_list->deleteAllItems(); // Clear existing entries - - // There should be only ESTATE_MAX_MANAGERS people in the list, but if the database gets more (SL-46107) don't - // truncate the list unless it's really big. Go ahead and show the extras so the user doesn't get confused, - // and they can still remove them. - for (S32 i = 0; i < num_estate_managers && i < (ESTATE_MAX_MANAGERS * 4); i++) - { - LLUUID id; - memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ - estate_manager_name_list->addNameItem(id); - } - panel->childSetEnabled("remove_estate_manager_btn", estate_manager_name_list->getFirstSelected() ? TRUE : FALSE); - estate_manager_name_list->sortByColumnIndex(0, TRUE); - } - } - - return true; -} - -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) -void LLFloaterRegionInfo::open() -{ - // We'll allow access to the estate tools for estate managers (and for the sim owner) - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) - { - LLViewerRegion* pRegion = gAgent.getRegion(); - if (!pRegion) - return; - - // Should be able to call LLRegion::canManageEstate() but then we can fake god like - if ( (!pRegion->isEstateManager()) && (pRegion->getOwner() != gAgent.getID()) ) - return; - } - - LLFloater::open(); -} -// [/RLVa:KB] +/** + * @file llfloaterregioninfo.cpp + * @author Aaron Brashears + * @brief Implementation of the region info and controls floater and panels. + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfloaterregioninfo.h" + +#include <algorithm> +#include <functional> + +#include "llcachename.h" +#include "lldir.h" +#include "lldispatcher.h" +#include "llglheaders.h" +#include "llregionflags.h" +#include "llstl.h" +#include "indra_constants.h" +#include "message.h" + +#include "llagent.h" +#include "llalertdialog.h" +#include "llappviewer.h" +#include "llfloateravatarpicker.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llfilepicker.h" +#include "llfloaterdaycycle.h" +#include "llfloatergodtools.h" // for send_sim_wide_deletes() +#include "llfloatertopobjects.h" // added to fix SL-32336 +#include "llfloatergroups.h" +#include "llfloatertelehub.h" +#include "llfloaterwindlight.h" +#include "llinventorymodel.h" +#include "lllineeditor.h" +#include "llalertdialog.h" +#include "llnamelistctrl.h" +#include "llsliderctrl.h" +#include "llspinctrl.h" +#include "lltabcontainer.h" +#include "lltextbox.h" +#include "llinventory.h" +#include "lltexturectrl.h" +#include "lltrans.h" +#include "llviewercontrol.h" +#include "lluictrlfactory.h" +#include "llviewerimage.h" +#include "llviewerimagelist.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llviewertexteditor.h" +#include "llviewerwindow.h" +#include "llvlcomposition.h" +#include "hippolimits.h" + +// [RLVa:KB] +#include "rlvhandler.h" +// [/RLVa:KB] + +#define ELAR_ENABLED 0 // Enable when server support is implemented + +const S32 TERRAIN_TEXTURE_COUNT = 4; +const S32 CORNER_COUNT = 4; + +///---------------------------------------------------------------------------- +/// Local class declaration +///---------------------------------------------------------------------------- + +class LLDispatchEstateUpdateInfo : public LLDispatchHandler +{ +public: + LLDispatchEstateUpdateInfo() {} + virtual ~LLDispatchEstateUpdateInfo() {} + virtual bool operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings); +}; + +class LLDispatchSetEstateAccess : public LLDispatchHandler +{ +public: + LLDispatchSetEstateAccess() {} + virtual ~LLDispatchSetEstateAccess() {} + virtual bool operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings); +}; + + +/* +void unpack_request_params( + LLMessageSystem* msg, + LLDispatcher::sparam_t& strings, + LLDispatcher::iparam_t& integers) +{ + char str_buf[MAX_STRING]; + S32 str_count = msg->getNumberOfBlocksFast(_PREHASH_StringData); + S32 i; + for (i = 0; i < str_count; ++i) + { + // we treat the SParam as binary data (since it might be an + // LLUUID in compressed form which may have embedded \0's,) + str_buf[0] = '\0'; + S32 data_size = msg->getSizeFast(_PREHASH_StringData, i, _PREHASH_SParam); + if (data_size >= 0) + { + msg->getBinaryDataFast(_PREHASH_StringData, _PREHASH_SParam, + str_buf, data_size, i, MAX_STRING - 1); + strings.push_back(std::string(str_buf, data_size)); + } + } + + U32 int_buf; + S32 int_count = msg->getNumberOfBlocksFast(_PREHASH_IntegerData); + for (i = 0; i < int_count; ++i) + { + msg->getU32("IntegerData", "IParam", int_buf, i); + integers.push_back(int_buf); + } +} +*/ + + + +bool estate_dispatch_initialized = false; + + +///---------------------------------------------------------------------------- +/// LLFloaterRegionInfo +///---------------------------------------------------------------------------- + +//S32 LLFloaterRegionInfo::sRequestSerial = 0; +LLUUID LLFloaterRegionInfo::sRequestInvoice; + +LLFloaterRegionInfo::LLFloaterRegionInfo(const LLSD& seed) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_region_info.xml", NULL, FALSE); +} + +BOOL LLFloaterRegionInfo::postBuild() +{ + mTab = getChild<LLTabContainer>("region_panels"); + + // contruct the panels + LLPanelRegionInfo* panel; + + panel = new LLPanelRegionGeneralInfo; + mInfoPanels.push_back(panel); + LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_general.xml"); + mTab->addTabPanel(panel, panel->getLabel(), TRUE); + + // We only use this panel on Aurora-based sims -- MC + std::string url = gAgent.getRegion()->getCapability("DispatchOpenRegionSettings"); + if (!url.empty()) + { + panel = new LLPanelRegionOpenSettingsInfo; + mInfoPanels.push_back(panel); + LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_open_region_settings.xml"); + mTab->addTabPanel(panel, panel->getLabel(), FALSE); + } + + panel = new LLPanelRegionDebugInfo; + mInfoPanels.push_back(panel); + LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_debug.xml"); + mTab->addTabPanel(panel, panel->getLabel(), FALSE); + + panel = new LLPanelRegionTextureInfo; + mInfoPanels.push_back(panel); + LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_texture.xml"); + mTab->addTabPanel(panel, panel->getLabel(), FALSE); + + panel = new LLPanelRegionTerrainInfo; + mInfoPanels.push_back(panel); + LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_terrain.xml"); + mTab->addTabPanel(panel, panel->getLabel(), FALSE); + + panel = new LLPanelEstateInfo; + mInfoPanels.push_back(panel); + LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_estate.xml"); + mTab->addTabPanel(panel, panel->getLabel(), FALSE); + + panel = new LLPanelEstateCovenant; + mInfoPanels.push_back(panel); + LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_covenant.xml"); + mTab->addTabPanel(panel, panel->getLabel(), FALSE); + + gMessageSystem->setHandlerFunc( + "EstateOwnerMessage", + &processEstateOwnerRequest); + + return TRUE; +} + +LLFloaterRegionInfo::~LLFloaterRegionInfo() +{ +} + +void LLFloaterRegionInfo::onOpen() +{ + LLRect rect = gSavedSettings.getRect("FloaterRegionInfo"); + S32 left, top; + gFloaterView->getNewFloaterPosition(&left, &top); + rect.translate(left,top); + + refreshFromRegion(gAgent.getRegion()); + requestRegionInfo(); + LLFloater::onOpen(); +} + +// static +void LLFloaterRegionInfo::requestRegionInfo() +{ + LLTabContainer* tab = findInstance()->getChild<LLTabContainer>("region_panels"); + + tab->getChild<LLPanel>("General")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("Debug")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("Terrain")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("Estate")->setCtrlsEnabled(FALSE); + tab->getChild<LLPanel>("RegionSettings")->setCtrlsEnabled(FALSE); + + // Must allow anyone to request the RegionInfo data + // so non-owners/non-gods can see the values. + // Therefore can't use an EstateOwnerMessage JC + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("RequestRegionInfo"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + gAgent.sendReliableMessage(); +} + +// static +void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) +{ + static LLDispatcher dispatch; + if(!findInstance()) + { + return; + } + + if (!estate_dispatch_initialized) + { + LLPanelEstateInfo::initDispatch(dispatch); + } + + LLTabContainer* tab = findInstance()->getChild<LLTabContainer>("region_panels"); + LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild<LLPanel>("Estate"); + + // unpack the message + std::string request; + LLUUID invoice; + LLDispatcher::sparam_t strings; + LLDispatcher::unpackMessage(msg, request, invoice, strings); + if(invoice != getLastInvoice()) + { + llwarns << "Mismatched Estate message: " << request << llendl; + return; + } + + //dispatch the message + dispatch.dispatch(request, invoice, strings); + + LLViewerRegion* region = gAgent.getRegion(); + panel->updateControls(region); +} + + +// static +void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) +{ + LLPanel* panel; + + llinfos << "LLFloaterRegionInfo::processRegionInfo" << llendl; + if(!findInstance()) + { + return; + } + + LLTabContainer* tab = findInstance()->getChild<LLTabContainer>("region_panels"); + + LLViewerRegion* region = gAgent.getRegion(); + BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); + + // extract message + std::string sim_name; + std::string sim_type = LLTrans::getString("land_type_unknown"); + U32 region_flags; + U8 agent_limit; + F32 object_bonus_factor; + U8 sim_access; + F32 water_height; + F32 terrain_raise_limit; + F32 terrain_lower_limit; + BOOL use_estate_sun; + F32 sun_hour; + msg->getString("RegionInfo", "SimName", sim_name); + msg->getU32("RegionInfo", "RegionFlags", region_flags); + msg->getU8("RegionInfo", "MaxAgents", agent_limit); + msg->getF32("RegionInfo", "ObjectBonusFactor", object_bonus_factor); + msg->getU8("RegionInfo", "SimAccess", sim_access); + msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_WaterHeight, water_height); + msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_TerrainRaiseLimit, terrain_raise_limit); + msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_TerrainLowerLimit, terrain_lower_limit); + msg->getBOOL("RegionInfo", "UseEstateSun", use_estate_sun); + // actually the "last set" sun hour, not the current sun hour. JC + msg->getF32("RegionInfo", "SunHour", sun_hour); + // the only reasonable way to decide if we actually have any data is to + // check to see if any of these fields have nonzero sizes + if (msg->getSize("RegionInfo2", "ProductSKU") > 0 || + msg->getSize("RegionInfo2", "ProductName") > 0) + { + msg->getString("RegionInfo2", "ProductName", sim_type); + } + + // GENERAL PANEL + panel = tab->getChild<LLPanel>("General"); + panel->childSetValue("region_text", LLSD(sim_name)); + panel->childSetValue("region_type", LLSD(sim_type)); + panel->childSetValue("version_channel_text", gLastVersionChannel); + + panel->childSetValue("block_terraform_check", (region_flags & REGION_FLAGS_BLOCK_TERRAFORM) ? TRUE : FALSE ); + panel->childSetValue("block_fly_check", (region_flags & REGION_FLAGS_BLOCK_FLY) ? TRUE : FALSE ); + panel->childSetValue("allow_damage_check", (region_flags & REGION_FLAGS_ALLOW_DAMAGE) ? TRUE : FALSE ); + panel->childSetValue("restrict_pushobject", (region_flags & REGION_FLAGS_RESTRICT_PUSHOBJECT) ? TRUE : FALSE ); + panel->childSetValue("allow_land_resell_check", (region_flags & REGION_FLAGS_BLOCK_LAND_RESELL) ? FALSE : TRUE ); + panel->childSetValue("allow_parcel_changes_check", (region_flags & REGION_FLAGS_ALLOW_PARCEL_CHANGES) ? TRUE : FALSE ); + panel->childSetValue("block_parcel_search_check", (region_flags & REGION_FLAGS_BLOCK_PARCEL_SEARCH) ? TRUE : FALSE ); + panel->childSetValue("agent_limit_spin", LLSD((F32)agent_limit) ); + panel->childSetValue("object_bonus_spin", LLSD(object_bonus_factor) ); + panel->childSetValue("access_combo", LLSD(sim_access) ); + + + // detect teen grid for maturity + + U32 parent_estate_id; + msg->getU32("RegionInfo", "ParentEstateID", parent_estate_id); + BOOL teen_grid = (parent_estate_id == 5); // *TODO add field to estate table and test that + panel->childSetEnabled("access_combo", gAgent.isGodlike() || (region && region->canManageEstate() && !teen_grid)); + panel->setCtrlsEnabled(allow_modify); + + // RegionSettings PANEL + panel = tab->getChild<LLPanel>("RegionSettings"); + panel->setCtrlsEnabled(allow_modify); + + // DEBUG PANEL + panel = tab->getChild<LLPanel>("Debug"); + + panel->childSetValue("region_text", LLSD(sim_name) ); + panel->childSetValue("disable_scripts_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SKIP_SCRIPTS)) ); + panel->childSetValue("disable_collisions_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SKIP_COLLISIONS)) ); + panel->childSetValue("disable_physics_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SKIP_PHYSICS)) ); + panel->setCtrlsEnabled(allow_modify); + + // TERRAIN PANEL + panel = tab->getChild<LLPanel>("Terrain"); + + panel->childSetValue("region_text", LLSD(sim_name)); + panel->childSetValue("water_height_spin", LLSD(water_height)); + panel->childSetValue("terrain_raise_spin", LLSD(terrain_raise_limit)); + panel->childSetValue("terrain_lower_spin", LLSD(terrain_lower_limit)); + panel->childSetValue("use_estate_sun_check", LLSD(use_estate_sun)); + + panel->childSetValue("fixed_sun_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SUN_FIXED))); + panel->childSetEnabled("fixed_sun_check", allow_modify && !use_estate_sun); + panel->childSetValue("sun_hour_slider", LLSD(sun_hour)); + panel->childSetEnabled("sun_hour_slider", allow_modify && !use_estate_sun); + panel->setCtrlsEnabled(allow_modify); + + getInstance()->refreshFromRegion( gAgent.getRegion() ); +} + +// static +LLPanelEstateInfo* LLFloaterRegionInfo::getPanelEstate() +{ + LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); + if (!floater) return NULL; + LLTabContainer* tab = floater->getChild<LLTabContainer>("region_panels"); + LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild<LLPanel>("Estate"); + return panel; +} + +// static +LLPanelEstateCovenant* LLFloaterRegionInfo::getPanelCovenant() +{ + LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); + if (!floater) return NULL; + LLTabContainer* tab = floater->getChild<LLTabContainer>("region_panels"); + LLPanelEstateCovenant* panel = (LLPanelEstateCovenant*)tab->getChild<LLPanel>("Covenant"); + return panel; +} + +// static +LLPanelRegionOpenSettingsInfo* LLFloaterRegionInfo::getPanelOpenSettings() +{ + LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); + if (floater) + { + LLTabContainer* tab = floater->getChild<LLTabContainer>("region_panels"); + LLPanelRegionOpenSettingsInfo* panel = (LLPanelRegionOpenSettingsInfo*)tab->getChild<LLPanel>("RegionSettings", FALSE, FALSE); + if (panel) + { + return panel; + } + } + return NULL; +} + +void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region) +{ + // call refresh from region on all panels + std::for_each( + mInfoPanels.begin(), + mInfoPanels.end(), + llbind2nd( +#if LL_WINDOWS + std::mem_fun1(&LLPanelRegionInfo::refreshFromRegion), +#else + std::mem_fun(&LLPanelRegionInfo::refreshFromRegion), +#endif + region)); +} + +// public +void LLFloaterRegionInfo::refresh() +{ + for(info_panels_t::iterator iter = mInfoPanels.begin(); + iter != mInfoPanels.end(); ++iter) + { + (*iter)->refresh(); + } +} + + +///---------------------------------------------------------------------------- +/// Local class implementation +///---------------------------------------------------------------------------- + +// +// LLPanelRegionInfo +// + +// static +void LLPanelRegionInfo::onBtnSet(void* user_data) +{ + LLPanelRegionInfo* panel = (LLPanelRegionInfo*)user_data; + if(!panel) return; + if (panel->sendUpdate()) + { + panel->disableButton("apply_btn"); + } +} + +//static +void LLPanelRegionInfo::onChangeChildCtrl(LLUICtrl* ctrl, void* user_data) +{ + if (ctrl) + { + LLPanelRegionInfo* panel = (LLPanelRegionInfo*) ctrl->getParent(); + panel->updateChild(ctrl); + } +} + +// static +// Enables the "set" button if it is not already enabled +void LLPanelRegionInfo::onChangeAnything(LLUICtrl* ctrl, void* user_data) +{ + LLPanelRegionInfo* panel = (LLPanelRegionInfo*)user_data; + if(panel) + { + panel->enableButton("apply_btn"); + panel->refresh(); + } +} + +// static +// Enables set button on change to line editor +void LLPanelRegionInfo::onChangeText(LLLineEditor* caller, void* user_data) +{ + // reuse the previous method + onChangeAnything(0, user_data); +} + + +// virtual +BOOL LLPanelRegionInfo::postBuild() +{ + childSetAction("apply_btn", onBtnSet, this); + childDisable("apply_btn"); + refresh(); + return TRUE; +} + +// virtual +void LLPanelRegionInfo::updateChild(LLUICtrl* child_ctr) +{ +} + +// virtual +bool LLPanelRegionInfo::refreshFromRegion(LLViewerRegion* region) +{ + if (region) mHost = region->getHost(); + return true; +} + +void LLPanelRegionInfo::sendEstateOwnerMessage( + LLMessageSystem* msg, + const std::string& request, + const LLUUID& invoice, + const strings_t& strings) +{ + llinfos << "Sending estate request '" << request << "'" << llendl; + msg->newMessage("EstateOwnerMessage"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used + msg->nextBlock("MethodData"); + msg->addString("Method", request); + msg->addUUID("Invoice", invoice); + if(strings.empty()) + { + msg->nextBlock("ParamList"); + msg->addString("Parameter", NULL); + } + else + { + strings_t::const_iterator it = strings.begin(); + strings_t::const_iterator end = strings.end(); + for(; it != end; ++it) + { + msg->nextBlock("ParamList"); + msg->addString("Parameter", *it); + } + } + msg->sendReliable(mHost); +} + +void LLPanelRegionInfo::enableButton(const std::string& btn_name, BOOL enable) +{ + childSetEnabled(btn_name, enable); +} + +void LLPanelRegionInfo::disableButton(const std::string& btn_name) +{ + childDisable(btn_name); +} + +void LLPanelRegionInfo::initCtrl(const std::string& name) +{ + childSetCommitCallback(name, onChangeAnything, this); +} + +void LLPanelRegionInfo::initHelpBtn(const std::string& name, const std::string& xml_alert) +{ + childSetAction(name, onClickHelp, new std::string(xml_alert)); +} + +// static +void LLPanelRegionInfo::onClickHelp(void* data) +{ + std::string* xml_alert = (std::string*)data; + LLNotifications::instance().add(*xml_alert); +} + +///////////////////////////////////////////////////////////////////////////// +// LLPanelRegionGeneralInfo +// +bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region) +{ + BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); + setCtrlsEnabled(allow_modify); + childDisable("apply_btn"); + childSetEnabled("access_text", allow_modify); + // childSetEnabled("access_combo", allow_modify); + // now set in processRegionInfo for teen grid detection + childSetEnabled("kick_btn", allow_modify); + childSetEnabled("kick_all_btn", allow_modify); + childSetEnabled("im_btn", allow_modify); + childSetEnabled("manage_telehub_btn", allow_modify); + + // Data gets filled in by processRegionInfo + + return LLPanelRegionInfo::refreshFromRegion(region); +} + +BOOL LLPanelRegionGeneralInfo::postBuild() +{ + // Enable the "Apply" button if something is changed. JC + initCtrl("block_terraform_check"); + initCtrl("block_fly_check"); + initCtrl("allow_damage_check"); + initCtrl("allow_land_resell_check"); + initCtrl("allow_parcel_changes_check"); + initCtrl("agent_limit_spin"); + initCtrl("object_bonus_spin"); + initCtrl("access_combo"); + initCtrl("restrict_pushobject"); + initCtrl("block_parcel_search_check"); + initCtrl("minimum_agent_age"); + + initHelpBtn("terraform_help", "HelpRegionBlockTerraform"); + initHelpBtn("fly_help", "HelpRegionBlockFly"); + initHelpBtn("damage_help", "HelpRegionAllowDamage"); + initHelpBtn("agent_limit_help", "HelpRegionAgentLimit"); + initHelpBtn("object_bonus_help", "HelpRegionObjectBonus"); + initHelpBtn("access_help", "HelpRegionMaturity"); + initHelpBtn("restrict_pushobject_help", "HelpRegionRestrictPushObject"); + initHelpBtn("land_resell_help", "HelpRegionLandResell"); + initHelpBtn("parcel_changes_help", "HelpParcelChanges"); + initHelpBtn("parcel_search_help", "HelpRegionSearch"); + + childSetAction("kick_btn", onClickKick, this); + childSetAction("kick_all_btn", onClickKickAll, this); + childSetAction("im_btn", onClickMessage, this); + childSetAction("manage_telehub_btn", onClickManageTelehub, this); + + return LLPanelRegionInfo::postBuild(); +} + +// static +void LLPanelRegionGeneralInfo::onClickKick(void* userdata) +{ + llinfos << "LLPanelRegionGeneralInfo::onClickKick" << llendl; + LLPanelRegionGeneralInfo* panelp = (LLPanelRegionGeneralInfo*)userdata; + + // this depends on the grandparent view being a floater + // in order to set up floater dependency + LLFloater* parent_floater = gFloaterView->getParentFloater(panelp); + LLFloater* child_floater = LLFloaterAvatarPicker::show(onKickCommit, userdata, FALSE, TRUE); + parent_floater->addDependentFloater(child_floater); +} + +// static +void LLPanelRegionGeneralInfo::onKickCommit(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* userdata) +{ + if (names.empty() || ids.empty()) return; + if(ids[0].notNull()) + { + LLPanelRegionGeneralInfo* self = (LLPanelRegionGeneralInfo*)userdata; + if(!self) return; + strings_t strings; + // [0] = our agent id + // [1] = target agent id + std::string buffer; + gAgent.getID().toString(buffer); + strings.push_back(buffer); + + ids[0].toString(buffer); + strings.push_back(strings_t::value_type(buffer)); + + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + self->sendEstateOwnerMessage(gMessageSystem, "teleporthomeuser", invoice, strings); + } +} + +// static +void LLPanelRegionGeneralInfo::onClickKickAll(void* userdata) +{ + llinfos << "LLPanelRegionGeneralInfo::onClickKickAll" << llendl; + LLNotifications::instance().add("KickUsersFromRegion", + LLSD(), + LLSD(), + boost::bind(&LLPanelRegionGeneralInfo::onKickAllCommit, (LLPanelRegionGeneralInfo*)userdata, _1, _2)); +} + +bool LLPanelRegionGeneralInfo::onKickAllCommit(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (option == 0) + { + strings_t strings; + // [0] = our agent id + std::string buffer; + gAgent.getID().toString(buffer); + strings.push_back(buffer); + + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + // historical message name + sendEstateOwnerMessage(gMessageSystem, "teleporthomeallusers", invoice, strings); + } + return false; +} + +// static +void LLPanelRegionGeneralInfo::onClickMessage(void* userdata) +{ + llinfos << "LLPanelRegionGeneralInfo::onClickMessage" << llendl; + LLNotifications::instance().add("MessageRegion", + LLSD(), + LLSD(), + boost::bind(&LLPanelRegionGeneralInfo::onMessageCommit, (LLPanelRegionGeneralInfo*)userdata, _1, _2)); +} + +// static +bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const LLSD& response) +{ + if(LLNotification::getSelectedOption(notification, response) != 0) return false; + + std::string text = response["message"].asString(); + if (text.empty()) return false; + + llinfos << "Message to everyone: " << text << llendl; + strings_t strings; + // [0] grid_x, unused here + // [1] grid_y, unused here + // [2] agent_id of sender + // [3] sender name + // [4] message + strings.push_back("-1"); + strings.push_back("-1"); + std::string buffer; + gAgent.getID().toString(buffer); + strings.push_back(buffer); + std::string name; + gAgent.buildFullname(name); + strings.push_back(strings_t::value_type(name)); + strings.push_back(strings_t::value_type(text)); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + sendEstateOwnerMessage(gMessageSystem, "simulatormessage", invoice, strings); + return false; +} + +// static +void LLPanelRegionGeneralInfo::onClickManageTelehub(void* data) +{ + LLFloaterRegionInfo::getInstance()->close(); + + LLFloaterTelehub::show(); +} + +// setregioninfo +// strings[0] = 'Y' - block terraform, 'N' - not +// strings[1] = 'Y' - block fly, 'N' - not +// strings[2] = 'Y' - allow damage, 'N' - not +// strings[3] = 'Y' - allow land sale, 'N' - not +// strings[4] = agent limit +// strings[5] = object bonus +// strings[6] = sim access (0 = unknown, 13 = PG, 21 = Mature, 42 = Adult) +// strings[7] = restrict pushobject +// strings[8] = 'Y' - allow parcel subdivide, 'N' - not +// strings[9] = 'Y' - block parcel search, 'N' - allow +BOOL LLPanelRegionGeneralInfo::sendUpdate() +{ + llinfos << "LLPanelRegionGeneralInfo::sendUpdate()" << llendl; + + // First try using a Cap. If that fails use the old method. + LLSD body; + std::string url = gAgent.getRegion()->getCapability("DispatchRegionInfo"); + if (!url.empty()) + { + body["block_terraform"] = childGetValue("block_terraform_check"); + body["block_fly"] = childGetValue("block_fly_check"); + body["allow_damage"] = childGetValue("allow_damage_check"); + body["allow_land_resell"] = childGetValue("allow_land_resell_check"); + body["agent_limit"] = childGetValue("agent_limit_spin"); + body["prim_bonus"] = childGetValue("object_bonus_spin"); + body["sim_access"] = childGetValue("access_combo"); + body["restrict_pushobject"] = childGetValue("restrict_pushobject"); + body["allow_parcel_changes"] = childGetValue("allow_parcel_changes_check"); + body["block_parcel_search"] = childGetValue("block_parcel_search_check"); + body["minimum_agent_age"] = childGetValue("minimum_agent_age"); + + LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); + } + else + { + strings_t strings; + std::string buffer; + + buffer = llformat("%s", (childGetValue("block_terraform_check").asBoolean() ? "Y" : "N")); + strings.push_back(strings_t::value_type(buffer)); + + buffer = llformat("%s", (childGetValue("block_fly_check").asBoolean() ? "Y" : "N")); + strings.push_back(strings_t::value_type(buffer)); + + buffer = llformat("%s", (childGetValue("allow_damage_check").asBoolean() ? "Y" : "N")); + strings.push_back(strings_t::value_type(buffer)); + + buffer = llformat("%s", (childGetValue("allow_land_resell_check").asBoolean() ? "Y" : "N")); + strings.push_back(strings_t::value_type(buffer)); + + F32 value = (F32)childGetValue("agent_limit_spin").asReal(); + buffer = llformat("%f", value); + strings.push_back(strings_t::value_type(buffer)); + + value = (F32)childGetValue("object_bonus_spin").asReal(); + buffer = llformat("%f", value); + strings.push_back(strings_t::value_type(buffer)); + + buffer = llformat("%d", childGetValue("access_combo").asInteger()); + strings.push_back(strings_t::value_type(buffer)); + + buffer = llformat("%s", (childGetValue("restrict_pushobject").asBoolean() ? "Y" : "N")); + strings.push_back(strings_t::value_type(buffer)); + + buffer = llformat("%s", (childGetValue("allow_parcel_changes_check").asBoolean() ? "Y" : "N")); + strings.push_back(strings_t::value_type(buffer)); + + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + sendEstateOwnerMessage(gMessageSystem, "setregioninfo", invoice, strings); + } + + // if we changed access levels, tell user about it + LLViewerRegion* region = gAgent.getRegion(); + if (region && (childGetValue("access_combo").asInteger() != region->getSimAccess()) ) + { + LLNotifications::instance().add("RegionMaturityChange"); + } + + return TRUE; +} + +///////////////////////////////////////////////////////////////////////////// +// LLPanelRegionOpenSettingsInfo +// +bool LLPanelRegionOpenSettingsInfo::refreshFromRegion(LLViewerRegion* region) +{ + // Data gets filled in by hippo manager + BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); + + childSetValue("draw_distance", gAgent.mDrawDistance); + childSetValue("force_draw_distance", gAgent.mLockedDrawDistance); + childSetValue("allow_minimap", LLSD(gHippoLimits->mAllowMinimap)); + childSetValue("allow_physical_prims", (gHippoLimits->mAllowPhysicalPrims == 1 ? TRUE : FALSE)); + childSetValue("max_drag_distance", LLSD(gHippoLimits->mMaxDragDistance)); + childSetValue("min_hole_size", LLSD(gHippoLimits->mMinHoleSize)); + childSetValue("max_hollow_size", LLSD(gHippoLimits->mMaxHollow)); + childSetValue("max_inventory_items_transfer", LLSD(gHippoLimits->mMaxInventoryItemsTransfer)); + childSetValue("max_link_count", LLSD(gHippoLimits->mMaxLinkedPrims)); + childSetValue("max_link_count_phys", LLSD(gHippoLimits->mMaxPhysLinkedPrims)); + childSetValue("max_phys_prim_scale", LLSD(gHippoLimits->mMaxPrimScale));//Todo:Fix + childSetValue("max_prim_scale", LLSD(gHippoLimits->mMaxPrimScale)); + childSetValue("min_prim_scale", LLSD(gHippoLimits->mMinPrimScale)); + childSetValue("render_water", LLSD(gHippoLimits->mRenderWater)); + childSetValue("show_tags", LLSD(gHippoLimits->mRenderName)); + childSetValue("max_groups", LLSD(gHippoLimits->mMaxAgentGroups)); + childSetValue("allow_parcel_windlight", LLSD(gHippoLimits->mAllowParcelWindLight)); + childSetValue("enable_teen_mode", LLSD(gHippoLimits->mEnableTeenMode)); + childSetValue("enforce_max_build", LLSD(gHippoLimits->mEnforceMaxBuild)); + + setCtrlsEnabled(allow_modify); + + return LLPanelRegionInfo::refreshFromRegion(region); +} + +BOOL LLPanelRegionOpenSettingsInfo::postBuild() +{ + // Enable the "Apply" button if something is changed. JC + initCtrl("draw_distance"); + initCtrl("force_draw_distance"); + initCtrl("max_drag_distance"); + initCtrl("max_prim_scale"); + initCtrl("min_prim_scale"); + initCtrl("max_phys_prim_scale"); + initCtrl("max_hollow_size"); + initCtrl("min_hole_size"); + initCtrl("max_link_count"); + initCtrl("max_link_count_phys"); + initCtrl("max_inventory_items_transfer"); + initCtrl("max_groups"); + initCtrl("render_water"); + initCtrl("allow_minimap"); + initCtrl("allow_physical_prims"); + initCtrl("enable_teen_mode"); + initCtrl("show_tags"); + initCtrl("allow_parcel_windlight"); + + initHelpBtn("force_draw_distance_help", "HelpForceDrawDistance"); + initHelpBtn("max_inventory_items_transfer_help", "HelpMaxInventoryItemsTransfer"); + initHelpBtn("max_groups_help", "HelpMaxGroups"); + initHelpBtn("render_water_help", "HelpRenderWater"); + initHelpBtn("allow_minimap_help", "HelpAllowMinimap"); + initHelpBtn("allow_physical_prims_help", "HelpAllowPhysicalPrims"); + initHelpBtn("enable_teen_mode_help", "HelpEnableTeenMode"); + initHelpBtn("show_tags_help", "HelpShowTags"); + initHelpBtn("allow_parcel_windlight_help", "HelpAllowParcelWindLight"); + + childSetAction("apply_ors_btn", onClickOrs, this); + + refreshFromRegion(gAgent.getRegion()); + + return LLPanelRegionInfo::postBuild(); +} + +// setregioninfo +// strings[0] = 'Y' - block terraform, 'N' - not +// strings[1] = 'Y' - block fly, 'N' - not +// strings[2] = 'Y' - allow damage, 'N' - not +// strings[3] = 'Y' - allow land sale, 'N' - not +// strings[4] = agent limit +// strings[5] = object bonus +// strings[6] = sim access (0 = unknown, 13 = PG, 21 = Mature, 42 = Adult) +// strings[7] = restrict pushobject +// strings[8] = 'Y' - allow parcel subdivide, 'N' - not +// strings[9] = 'Y' - block parcel search, 'N' - allow +void LLPanelRegionOpenSettingsInfo::onClickOrs(void* userdata) +{ + LLPanelRegionOpenSettingsInfo* self; + self = (LLPanelRegionOpenSettingsInfo*)userdata; + + llinfos << "LLPanelRegionOpenSettingsInfo::onClickOrs()" << llendl; + + LLSD body; + std::string url = gAgent.getRegion()->getCapability("DispatchOpenRegionSettings"); + if (!url.empty()) + { + body["draw_distance"] = self->childGetValue("draw_distance"); + body["force_draw_distance"] = self->childGetValue("force_draw_distance"); + body["allow_minimap"] = self->childGetValue("allow_minimap"); + body["allow_physical_prims"] = self->childGetValue("allow_physical_prims"); + body["max_drag_distance"] = self->childGetValue("max_drag_distance"); + body["min_hole_size"] = self->childGetValue("min_hole_size"); + body["max_hollow_size"] = self->childGetValue("max_hollow_size"); + body["max_inventory_items_transfer"] = self->childGetValue("max_inventory_items_transfer"); + body["max_link_count"] = self->childGetValue("max_link_count"); + body["max_link_count_phys"] = self->childGetValue("max_link_count_phys"); + body["max_phys_prim_scale"] = self->childGetValue("max_phys_prim_scale"); + body["max_prim_scale"] = self->childGetValue("max_prim_scale"); + body["min_prim_scale"] = self->childGetValue("min_prim_scale"); + body["render_water"] = self->childGetValue("render_water"); + body["show_tags"] = self->childGetValue("show_tags"); + body["max_groups"] = self->childGetValue("max_groups"); + body["allow_parcel_windlight"] = self->childGetValue("allow_parcel_windlight"); + body["enable_teen_mode"] = self->childGetValue("enable_teen_mode"); + body["enforce_max_build"] = self->childGetValue("enforce_max_build"); + + LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); + } +} + +///////////////////////////////////////////////////////////////////////////// +// LLPanelRegionDebugInfo +///////////////////////////////////////////////////////////////////////////// +BOOL LLPanelRegionDebugInfo::postBuild() +{ + LLPanelRegionInfo::postBuild(); + initCtrl("disable_scripts_check"); + initCtrl("disable_collisions_check"); + initCtrl("disable_physics_check"); + + initHelpBtn("disable_scripts_help", "HelpRegionDisableScripts"); + initHelpBtn("disable_collisions_help", "HelpRegionDisableCollisions"); + initHelpBtn("disable_physics_help", "HelpRegionDisablePhysics"); + initHelpBtn("top_colliders_help", "HelpRegionTopColliders"); + initHelpBtn("top_scripts_help", "HelpRegionTopScripts"); + initHelpBtn("restart_help", "HelpRegionRestart"); + initHelpBtn("minimum_agent_age_help", "HelpRegionMinimumAge"); + + + childSetAction("choose_avatar_btn", onClickChooseAvatar, this); + childSetAction("return_btn", onClickReturn, this); + childSetAction("top_colliders_btn", onClickTopColliders, this); + childSetAction("top_scripts_btn", onClickTopScripts, this); + childSetAction("restart_btn", onClickRestart, this); + childSetAction("cancel_restart_btn", onClickCancelRestart, this); + + return TRUE; +} + +// virtual +bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region) +{ + BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); + setCtrlsEnabled(allow_modify); + childDisable("apply_btn"); + childDisable("target_avatar_name"); + + childSetEnabled("choose_avatar_btn", allow_modify); + childSetEnabled("return_scripts", allow_modify && !mTargetAvatar.isNull()); + childSetEnabled("return_other_land", allow_modify && !mTargetAvatar.isNull()); + childSetEnabled("return_estate_wide", allow_modify && !mTargetAvatar.isNull()); + childSetEnabled("return_btn", allow_modify && !mTargetAvatar.isNull()); + childSetEnabled("top_colliders_btn", allow_modify); + childSetEnabled("top_scripts_btn", allow_modify); + childSetEnabled("restart_btn", allow_modify); + childSetEnabled("cancel_restart_btn", allow_modify); + + return LLPanelRegionInfo::refreshFromRegion(region); +} + +// virtual +BOOL LLPanelRegionDebugInfo::sendUpdate() +{ + llinfos << "LLPanelRegionDebugInfo::sendUpdate" << llendl; + strings_t strings; + std::string buffer; + + buffer = llformat("%s", (childGetValue("disable_scripts_check").asBoolean() ? "Y" : "N")); + strings.push_back(buffer); + + buffer = llformat("%s", (childGetValue("disable_collisions_check").asBoolean() ? "Y" : "N")); + strings.push_back(buffer); + + buffer = llformat("%s", (childGetValue("disable_physics_check").asBoolean() ? "Y" : "N")); + strings.push_back(buffer); + + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + sendEstateOwnerMessage(gMessageSystem, "setregiondebug", invoice, strings); + return TRUE; +} + +void LLPanelRegionDebugInfo::onClickChooseAvatar(void* data) +{ + LLFloaterAvatarPicker::show(callbackAvatarID, data, FALSE, TRUE); +} + +// static +void LLPanelRegionDebugInfo::callbackAvatarID(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* data) +{ + LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*) data; + if (ids.empty() || names.empty()) return; + self->mTargetAvatar = ids[0]; + self->childSetValue("target_avatar_name", LLSD(names[0])); + self->refreshFromRegion( gAgent.getRegion() ); +} + +// static +void LLPanelRegionDebugInfo::onClickReturn(void* data) +{ + LLPanelRegionDebugInfo* panelp = (LLPanelRegionDebugInfo*) data; + if (panelp->mTargetAvatar.isNull()) return; + + LLSD args; + args["USER_NAME"] = panelp->childGetValue("target_avatar_name").asString(); + LLSD payload; + payload["avatar_id"] = panelp->mTargetAvatar; + + U32 flags = SWD_ALWAYS_RETURN_OBJECTS; + + if (panelp->childGetValue("return_scripts").asBoolean()) + { + flags |= SWD_SCRIPTED_ONLY; + } + + if (panelp->childGetValue("return_other_land").asBoolean()) + { + flags |= SWD_OTHERS_LAND_ONLY; + } + payload["flags"] = int(flags); + payload["return_estate_wide"] = panelp->childGetValue("return_estate_wide").asBoolean(); + LLNotifications::instance().add("EstateObjectReturn", args, payload, + boost::bind(&LLPanelRegionDebugInfo::callbackReturn, panelp, _1, _2)); +} + +bool LLPanelRegionDebugInfo::callbackReturn(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (option != 0) return false; + + LLUUID target_avatar = notification["payload"]["avatar_id"].asUUID(); + if (!target_avatar.isNull()) + { + U32 flags = notification["payload"]["flags"].asInteger(); + bool return_estate_wide = notification["payload"]["return_estate_wide"]; + if (return_estate_wide) + { + // send as estate message - routed by spaceserver to all regions in estate + strings_t strings; + strings.push_back(llformat("%d", flags)); + strings.push_back(target_avatar.asString()); + + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + + sendEstateOwnerMessage(gMessageSystem, "estateobjectreturn", invoice, strings); + } + else + { + // send to this simulator only + send_sim_wide_deletes(target_avatar, flags); + } + } + return false; +} + + +// static +void LLPanelRegionDebugInfo::onClickTopColliders(void* data) +{ + LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*)data; + strings_t strings; + strings.push_back("1"); // one physics step + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + LLFloaterTopObjects::show(); + LLFloaterTopObjects::clearList(); + self->sendEstateOwnerMessage(gMessageSystem, "colliders", invoice, strings); +} + +// static +void LLPanelRegionDebugInfo::onClickTopScripts(void* data) +{ + LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*)data; + strings_t strings; + strings.push_back("6"); // top 5 scripts + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + LLFloaterTopObjects::show(); + LLFloaterTopObjects::clearList(); + self->sendEstateOwnerMessage(gMessageSystem, "scripts", invoice, strings); +} + +// static +void LLPanelRegionDebugInfo::onClickRestart(void* data) +{ + LLNotifications::instance().add("ConfirmRestart", LLSD(), LLSD(), + boost::bind(&LLPanelRegionDebugInfo::callbackRestart, (LLPanelRegionDebugInfo*)data, _1, _2)); +} + +bool LLPanelRegionDebugInfo::callbackRestart(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (option != 0) return false; + + strings_t strings; + strings.push_back("120"); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + sendEstateOwnerMessage(gMessageSystem, "restart", invoice, strings); + return false; +} + +// static +void LLPanelRegionDebugInfo::onClickCancelRestart(void* data) +{ + LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*)data; + strings_t strings; + strings.push_back("-1"); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + self->sendEstateOwnerMessage(gMessageSystem, "restart", invoice, strings); +} + + +///////////////////////////////////////////////////////////////////////////// +// LLPanelRegionTextureInfo +// +LLPanelRegionTextureInfo::LLPanelRegionTextureInfo() : LLPanelRegionInfo() +{ + // nothing. +} + +bool LLPanelRegionTextureInfo::refreshFromRegion(LLViewerRegion* region) +{ + BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); + setCtrlsEnabled(allow_modify); + childDisable("apply_btn"); + + if (region) + { + childSetValue("region_text", LLSD(region->getName())); + } + else + { + childSetValue("region_text", LLSD("")); + } + + if (!region) return LLPanelRegionInfo::refreshFromRegion(region); + + LLVLComposition* compp = region->getComposition(); + LLTextureCtrl* texture_ctrl; + std::string buffer; + for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) + { + buffer = llformat("texture_detail_%d", i); + texture_ctrl = getChild<LLTextureCtrl>(buffer); + if(texture_ctrl) + { + lldebugs << "Detail Texture " << i << ": " + << compp->getDetailTextureID(i) << llendl; + LLUUID tmp_id(compp->getDetailTextureID(i)); + texture_ctrl->setImageAssetID(tmp_id); + } + } + + for(S32 i = 0; i < CORNER_COUNT; ++i) + { + buffer = llformat("height_start_spin_%d", i); + childSetValue(buffer, LLSD(compp->getStartHeight(i))); + buffer = llformat("height_range_spin_%d", i); + childSetValue(buffer, LLSD(compp->getHeightRange(i))); + } + + // Call the parent for common book-keeping + return LLPanelRegionInfo::refreshFromRegion(region); +} + + +BOOL LLPanelRegionTextureInfo::postBuild() +{ + LLPanelRegionInfo::postBuild(); + std::string buffer; + for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) + { + buffer = llformat("texture_detail_%d", i); + initCtrl(buffer); + } + + for(S32 i = 0; i < CORNER_COUNT; ++i) + { + buffer = llformat("height_start_spin_%d", i); + initCtrl(buffer); + buffer = llformat("height_range_spin_%d", i); + initCtrl(buffer); + } + +// LLButton* btn = new LLButton("dump", LLRect(0, 20, 100, 0), "", onClickDump, this); +// btn->setFollows(FOLLOWS_TOP|FOLLOWS_LEFT); +// addChild(btn); + + return LLPanelRegionInfo::postBuild(); +} + +BOOL LLPanelRegionTextureInfo::sendUpdate() +{ + llinfos << "LLPanelRegionTextureInfo::sendUpdate()" << llendl; + + // Make sure user hasn't chosen wacky textures. + if (!validateTextureSizes()) + { + return FALSE; + } + + LLTextureCtrl* texture_ctrl; + std::string buffer; + std::string id_str; + LLMessageSystem* msg = gMessageSystem; + strings_t strings; + + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + + for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) + { + buffer = llformat("texture_detail_%d", i); + texture_ctrl = getChild<LLTextureCtrl>(buffer); + if(texture_ctrl) + { + LLUUID tmp_id(texture_ctrl->getImageAssetID()); + tmp_id.toString(id_str); + buffer = llformat("%d %s", i, id_str.c_str()); + strings.push_back(buffer); + } + } + sendEstateOwnerMessage(msg, "texturedetail", invoice, strings); + strings.clear(); + for(S32 i = 0; i < CORNER_COUNT; ++i) + { + buffer = llformat("height_start_spin_%d", i); + std::string buffer2 = llformat("height_range_spin_%d", i); + std::string buffer3 = llformat("%d %f %f", i, (F32)childGetValue(buffer).asReal(), (F32)childGetValue(buffer2).asReal()); + strings.push_back(buffer3); + } + sendEstateOwnerMessage(msg, "textureheights", invoice, strings); + strings.clear(); + sendEstateOwnerMessage(msg, "texturecommit", invoice, strings); + return TRUE; +} + +BOOL LLPanelRegionTextureInfo::validateTextureSizes() +{ + for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i) + { + std::string buffer; + buffer = llformat("texture_detail_%d", i); + LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>(buffer); + if (!texture_ctrl) continue; + + LLUUID image_asset_id = texture_ctrl->getImageAssetID(); + LLViewerImage* img = gImageList.getImage(image_asset_id); + S32 components = img->getComponents(); + // Must ask for highest resolution version's width. JC + S32 width = img->getWidth(0); + S32 height = img->getHeight(0); + + //llinfos << "texture detail " << i << " is " << width << "x" << height << "x" << components << llendl; + + if (components != 3) + { + LLSD args; + args["TEXTURE_NUM"] = i+1; + args["TEXTURE_BIT_DEPTH"] = llformat("%d",components * 8); + LLNotifications::instance().add("InvalidTerrainBitDepth", args); + return FALSE; + } + + if (width > 512 || height > 512) + { + + LLSD args; + args["TEXTURE_NUM"] = i+1; + args["TEXTURE_SIZE_X"] = width; + args["TEXTURE_SIZE_Y"] = height; + LLNotifications::instance().add("InvalidTerrainSize", args); + return FALSE; + + } + } + + return TRUE; +} + + +// static +void LLPanelRegionTextureInfo::onClickDump(void* data) +{ + llinfos << "LLPanelRegionTextureInfo::onClickDump()" << llendl; +} + + +///////////////////////////////////////////////////////////////////////////// +// LLPanelRegionTerrainInfo +///////////////////////////////////////////////////////////////////////////// +BOOL LLPanelRegionTerrainInfo::postBuild() +{ + LLPanelRegionInfo::postBuild(); + + initHelpBtn("water_height_help", "HelpRegionWaterHeight"); + initHelpBtn("terrain_raise_help", "HelpRegionTerrainRaise"); + initHelpBtn("terrain_lower_help", "HelpRegionTerrainLower"); + initHelpBtn("upload_raw_help", "HelpRegionUploadRaw"); + initHelpBtn("download_raw_help", "HelpRegionDownloadRaw"); + initHelpBtn("use_estate_sun_help", "HelpRegionUseEstateSun"); + initHelpBtn("fixed_sun_help", "HelpRegionFixedSun"); + initHelpBtn("bake_terrain_help", "HelpRegionBakeTerrain"); + + initCtrl("water_height_spin"); + initCtrl("terrain_raise_spin"); + initCtrl("terrain_lower_spin"); + + initCtrl("fixed_sun_check"); + childSetCommitCallback("fixed_sun_check", onChangeFixedSun, this); + childSetCommitCallback("use_estate_sun_check", onChangeUseEstateTime, this); + childSetCommitCallback("sun_hour_slider", onChangeSunHour, this); + + childSetAction("download_raw_btn", onClickDownloadRaw, this); + childSetAction("upload_raw_btn", onClickUploadRaw, this); + childSetAction("bake_terrain_btn", onClickBakeTerrain, this); + + return TRUE; +} + +// virtual +bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) +{ + llinfos << "LLPanelRegionTerrainInfo::refreshFromRegion" << llendl; + + BOOL owner_or_god = gAgent.isGodlike() + || (region && (region->getOwner() == gAgent.getID())); + BOOL owner_or_god_or_manager = owner_or_god + || (region && region->isEstateManager()); + setCtrlsEnabled(owner_or_god_or_manager); + childDisable("apply_btn"); + + childSetEnabled("download_raw_btn", owner_or_god); + childSetEnabled("upload_raw_btn", owner_or_god); + childSetEnabled("bake_terrain_btn", owner_or_god); + + return LLPanelRegionInfo::refreshFromRegion(region); +} + +// virtual +BOOL LLPanelRegionTerrainInfo::sendUpdate() +{ + llinfos << "LLPanelRegionTerrainInfo::sendUpdate" << llendl; + std::string buffer; + strings_t strings; + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + + buffer = llformat("%f", (F32)childGetValue("water_height_spin").asReal()); + strings.push_back(buffer); + buffer = llformat("%f", (F32)childGetValue("terrain_raise_spin").asReal()); + strings.push_back(buffer); + buffer = llformat("%f", (F32)childGetValue("terrain_lower_spin").asReal()); + strings.push_back(buffer); + buffer = llformat("%s", (childGetValue("use_estate_sun_check").asBoolean() ? "Y" : "N")); + strings.push_back(buffer); + buffer = llformat("%s", (childGetValue("fixed_sun_check").asBoolean() ? "Y" : "N")); + strings.push_back(buffer); + buffer = llformat("%f", (F32)childGetValue("sun_hour_slider").asReal() ); + strings.push_back(buffer); + + // Grab estate information in case the user decided to set the + // region back to estate time. JC + LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); + if (!floater) return true; + + LLTabContainer* tab = floater->getChild<LLTabContainer>("region_panels"); + if (!tab) return true; + + LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild<LLPanel>("Estate"); + if (!panel) return true; + + BOOL estate_global_time = panel->getGlobalTime(); + BOOL estate_fixed_sun = panel->getFixedSun(); + F32 estate_sun_hour; + if (estate_global_time) + { + estate_sun_hour = 0.f; + } + else + { + estate_sun_hour = panel->getSunHour(); + } + + buffer = llformat("%s", (estate_global_time ? "Y" : "N") ); + strings.push_back(buffer); + buffer = llformat("%s", (estate_fixed_sun ? "Y" : "N") ); + strings.push_back(buffer); + buffer = llformat("%f", estate_sun_hour); + strings.push_back(buffer); + + sendEstateOwnerMessage(gMessageSystem, "setregionterrain", invoice, strings); + return TRUE; +} + +// static +void LLPanelRegionTerrainInfo::onChangeUseEstateTime(LLUICtrl* ctrl, void* user_data) +{ + LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) user_data; + if (!panel) return; + BOOL use_estate_sun = panel->childGetValue("use_estate_sun_check").asBoolean(); + panel->childSetEnabled("fixed_sun_check", !use_estate_sun); + panel->childSetEnabled("sun_hour_slider", !use_estate_sun); + if (use_estate_sun) + { + panel->childSetValue("fixed_sun_check", LLSD(FALSE)); + panel->childSetValue("sun_hour_slider", LLSD(0.f)); + } + panel->childEnable("apply_btn"); +} + +// static +void LLPanelRegionTerrainInfo::onChangeFixedSun(LLUICtrl* ctrl, void* user_data) +{ + LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) user_data; + if (!panel) return; + // Just enable the apply button. We let the sun-hour slider be enabled + // for both fixed-sun and non-fixed-sun. JC + panel->childEnable("apply_btn"); +} + +// static +void LLPanelRegionTerrainInfo::onChangeSunHour(LLUICtrl* ctrl, void*) +{ + // can't use userdata to get panel, slider uses it internally + LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) ctrl->getParent(); + if (!panel) return; + panel->childEnable("apply_btn"); +} + +// static +void LLPanelRegionTerrainInfo::onClickDownloadRaw(void* data) +{ + LLFilePicker& picker = LLFilePicker::instance(); + if (!picker.getSaveFile(LLFilePicker::FFSAVE_RAW, "terrain.raw")) + { + llwarns << "No file" << llendl; + return; + } + std::string filepath = picker.getFirstFile(); + gXferManager->expectFileForRequest(filepath); + + LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; + strings_t strings; + strings.push_back("download filename"); + strings.push_back(filepath); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); +} + +// static +void LLPanelRegionTerrainInfo::onClickUploadRaw(void* data) +{ + LLFilePicker& picker = LLFilePicker::instance(); + if (!picker.getOpenFile(LLFilePicker::FFLOAD_RAW)) + { + llwarns << "No file" << llendl; + return; + } + std::string filepath = picker.getFirstFile(); + gXferManager->expectFileForTransfer(filepath); + + LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; + strings_t strings; + strings.push_back("upload filename"); + strings.push_back(filepath); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); + + LLNotifications::instance().add("RawUploadStarted"); +} + +// static +void LLPanelRegionTerrainInfo::onClickBakeTerrain(void* data) +{ + LLNotifications::instance().add( + LLNotification::Params("ConfirmBakeTerrain") + .functor(boost::bind(&LLPanelRegionTerrainInfo::callbackBakeTerrain, (LLPanelRegionTerrainInfo*)data, _1, _2))); +} + +bool LLPanelRegionTerrainInfo::callbackBakeTerrain(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (option != 0) return false; + + strings_t strings; + strings.push_back("bake"); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); + return false; +} + +///////////////////////////////////////////////////////////////////////////// +// LLPanelEstateInfo +// + +LLPanelEstateInfo::LLPanelEstateInfo() +: LLPanelRegionInfo(), + mEstateID(0) // invalid +{ +} + +// static +void LLPanelEstateInfo::initDispatch(LLDispatcher& dispatch) +{ + std::string name; + +// name.assign("setowner"); +// static LLDispatchSetEstateOwner set_owner; +// dispatch.addHandler(name, &set_owner); + + name.assign("estateupdateinfo"); + static LLDispatchEstateUpdateInfo estate_update_info; + dispatch.addHandler(name, &estate_update_info); + + name.assign("setaccess"); + static LLDispatchSetEstateAccess set_access; + dispatch.addHandler(name, &set_access); + + estate_dispatch_initialized = true; +} + +// static +// Disables the sun-hour slider and the use fixed time check if the use global time is check +void LLPanelEstateInfo::onChangeUseGlobalTime(LLUICtrl* ctrl, void* user_data) +{ + LLPanelEstateInfo* panel = (LLPanelEstateInfo*) user_data; + if (panel) + { + bool enabled = !panel->childGetValue("use_global_time_check").asBoolean(); + panel->childSetEnabled("sun_hour_slider", enabled); + panel->childSetEnabled("fixed_sun_check", enabled); + panel->childSetValue("fixed_sun_check", LLSD(FALSE)); + panel->enableButton("apply_btn"); + } +} + +// Enables the sun-hour slider if the fixed-sun checkbox is set +void LLPanelEstateInfo::onChangeFixedSun(LLUICtrl* ctrl, void* user_data) +{ + LLPanelEstateInfo* panel = (LLPanelEstateInfo*) user_data; + if (panel) + { + bool enabled = !panel->childGetValue("fixed_sun_check").asBoolean(); + panel->childSetEnabled("use_global_time_check", enabled); + panel->childSetValue("use_global_time_check", LLSD(FALSE)); + panel->enableButton("apply_btn"); + } +} + + + + +//--------------------------------------------------------------------------- +// Add/Remove estate access button callbacks +//--------------------------------------------------------------------------- +void LLPanelEstateInfo::onClickEditSky(void* user_data) +{ + LLFloaterWindLight::show(); +} + +void LLPanelEstateInfo::onClickEditDayCycle(void* user_data) +{ + LLFloaterDayCycle::show(); +} + +// static +void LLPanelEstateInfo::onClickAddAllowedAgent(void* user_data) +{ + LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data; + LLCtrlListInterface *list = self->childGetListInterface("allowed_avatar_name_list"); + if (!list) return; + if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) + { + //args + + LLSD args; + args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + LLNotifications::instance().add("MaxAllowedAgentOnRegion", args); + return; + } + accessAddCore(ESTATE_ACCESS_ALLOWED_AGENT_ADD, "EstateAllowedAgentAdd"); +} + +// static +void LLPanelEstateInfo::onClickRemoveAllowedAgent(void* user_data) +{ + accessRemoveCore(ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, "EstateAllowedAgentRemove", "allowed_avatar_name_list"); +} + +// static +void LLPanelEstateInfo::onClickAddAllowedGroup(void* user_data) +{ + LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data; + LLCtrlListInterface *list = self->childGetListInterface("allowed_group_name_list"); + if (!list) return; + if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) + { + LLSD args; + args["MAX_GROUPS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + LLNotifications::instance().add("MaxAllowedGroupsOnRegion", args); + return; + } + + LLNotification::Params params("ChangeLindenAccess"); + params.functor(boost::bind(&LLPanelEstateInfo::addAllowedGroup, self, _1, _2)); + if (isLindenEstate()) + { + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } +} + +bool LLPanelEstateInfo::addAllowedGroup(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (option != 0) return false; + + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + + LLFloaterGroupPicker* widget; + widget = LLFloaterGroupPicker::showInstance(LLSD(gAgent.getID())); + if (widget) + { + widget->setSelectCallback(addAllowedGroup2, NULL); + if (parent_floater) + { + LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, widget); + widget->setOrigin(new_rect.mLeft, new_rect.mBottom); + parent_floater->addDependentFloater(widget); + } + } + + return false; +} + +// static +void LLPanelEstateInfo::onClickRemoveAllowedGroup(void* user_data) +{ + accessRemoveCore(ESTATE_ACCESS_ALLOWED_GROUP_REMOVE, "EstateAllowedGroupRemove", "allowed_group_name_list"); +} + +// static +void LLPanelEstateInfo::onClickAddBannedAgent(void* user_data) +{ + LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data; + LLCtrlListInterface *list = self->childGetListInterface("banned_avatar_name_list"); + if (!list) return; + if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) + { + LLSD args; + args["MAX_BANNED"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + LLNotifications::instance().add("MaxBannedAgentsOnRegion", args); + return; + } + accessAddCore(ESTATE_ACCESS_BANNED_AGENT_ADD, "EstateBannedAgentAdd"); +} + +// static +void LLPanelEstateInfo::onClickRemoveBannedAgent(void* user_data) +{ + accessRemoveCore(ESTATE_ACCESS_BANNED_AGENT_REMOVE, "EstateBannedAgentRemove", "banned_avatar_name_list"); +} + +// static +void LLPanelEstateInfo::onClickAddEstateManager(void* user_data) +{ + LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data; + LLCtrlListInterface *list = self->childGetListInterface("estate_manager_name_list"); + if (!list) return; + if (list->getItemCount() >= ESTATE_MAX_MANAGERS) + { // Tell user they can't add more managers + LLSD args; + args["MAX_MANAGER"] = llformat("%d",ESTATE_MAX_MANAGERS); + LLNotifications::instance().add("MaxManagersOnRegion", args); + } + else + { // Go pick managers to add + accessAddCore(ESTATE_ACCESS_MANAGER_ADD, "EstateManagerAdd"); + } +} + +// static +void LLPanelEstateInfo::onClickRemoveEstateManager(void* user_data) +{ + accessRemoveCore(ESTATE_ACCESS_MANAGER_REMOVE, "EstateManagerRemove", "estate_manager_name_list"); +} + +//--------------------------------------------------------------------------- +// Kick from estate methods +//--------------------------------------------------------------------------- +struct LLKickFromEstateInfo +{ + LLPanelEstateInfo *mEstatePanelp; + LLUUID mAgentID; +}; + +void LLPanelEstateInfo::onClickKickUser(void *user_data) +{ + LLPanelEstateInfo* panelp = (LLPanelEstateInfo*)user_data; + + // this depends on the grandparent view being a floater + // in order to set up floater dependency + LLFloater* parent_floater = gFloaterView->getParentFloater(panelp); + LLFloater* child_floater = LLFloaterAvatarPicker::show(LLPanelEstateInfo::onKickUserCommit, user_data, FALSE, TRUE); + parent_floater->addDependentFloater(child_floater); +} + +void LLPanelEstateInfo::onKickUserCommit(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* userdata) +{ + if (names.empty() || ids.empty()) return; + + //check to make sure there is one valid user and id + if( (ids[0].isNull()) || + (names[0].length() == 0) ) + { + return; + } + + LLPanelEstateInfo* self = (LLPanelEstateInfo*)userdata; + if(!self) return; + + //keep track of what user they want to kick and other misc info + LLKickFromEstateInfo *kick_info = new LLKickFromEstateInfo(); + kick_info->mEstatePanelp = self; + kick_info->mAgentID = ids[0]; + + //Bring up a confirmation dialog + LLSD args; + args["EVIL_USER"] = names[0]; + LLSD payload; + payload["agent_id"] = ids[0]; + LLNotifications::instance().add("EstateKickUser", args, payload, boost::bind(&LLPanelEstateInfo::kickUserConfirm, self, _1, _2)); + +} + +bool LLPanelEstateInfo::kickUserConfirm(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case 0: + { + //Kick User + strings_t strings; + strings.push_back(notification["payload"]["agent_id"].asString()); + + sendEstateOwnerMessage(gMessageSystem, "kickestate", LLFloaterRegionInfo::getLastInvoice(), strings); + break; + } + default: + break; + } + return false; +} + +//--------------------------------------------------------------------------- +// Core Add/Remove estate access methods +// TODO: INTERNATIONAL: don't build message text here; +// instead, create multiple translatable messages and choose +// one based on the status. +//--------------------------------------------------------------------------- +std::string all_estates_text() +{ + LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); + if (!panel) return "(error)"; + + std::string owner = panel->getOwnerName(); + + LLViewerRegion* region = gAgent.getRegion(); + if (gAgent.isGodlike()) + { + return llformat("all estates\nowned by %s", owner.c_str()); + } + else if (region && region->getOwner() == gAgent.getID()) + { + return "all estates you own"; + } + else if (region && region->isEstateManager()) + { + return llformat("all estates that\nyou manage for %s", owner.c_str()); + } + else + { + return "(error)"; + } +} + +// static +bool LLPanelEstateInfo::isLindenEstate() +{ + LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); + if (!panel) return false; + + U32 estate_id = panel->getEstateID(); + return (estate_id <= ESTATE_LAST_LINDEN); +} + +typedef std::vector<LLUUID> AgentOrGroupIDsVector; +struct LLEstateAccessChangeInfo +{ + LLEstateAccessChangeInfo(const LLSD& sd) + { + mDialogName = sd["dialog_name"].asString(); + mOperationFlag = (U32)sd["operation"].asInteger(); + LLSD::array_const_iterator end_it = sd["allowed_ids"].endArray(); + for (LLSD::array_const_iterator id_it = sd["allowed_ids"].beginArray(); + id_it != end_it; + ++id_it) + { + mAgentOrGroupIDs.push_back(id_it->asUUID()); + } + } + + const LLSD asLLSD() const + { + LLSD sd; + sd["name"] = mDialogName; + sd["operation"] = (S32)mOperationFlag; + for (AgentOrGroupIDsVector::const_iterator it = mAgentOrGroupIDs.begin(); + it != mAgentOrGroupIDs.end(); + ++it) + { + sd["allowed_ids"].append(*it); + } + return sd; + } + + U32 mOperationFlag; // ESTATE_ACCESS_BANNED_AGENT_ADD, _REMOVE, etc. + std::string mDialogName; + AgentOrGroupIDsVector mAgentOrGroupIDs; // List of agent IDs to apply to this change +}; + +// Special case callback for groups, since it has different callback format than names +// static +void LLPanelEstateInfo::addAllowedGroup2(LLUUID id, void* user_data) +{ + LLSD payload; + payload["operation"] = (S32)ESTATE_ACCESS_ALLOWED_GROUP_ADD; + payload["dialog_name"] = "EstateAllowedGroupAdd"; + payload["allowed_ids"].append(id); + + LLSD args; + args["ALL_ESTATES"] = all_estates_text(); + + LLNotification::Params params("EstateAllowedGroupAdd"); + params.payload(payload) + .substitutions(args) + .functor(accessCoreConfirm); + if (isLindenEstate()) + { + LLNotifications::instance().forceResponse(params, 0); + } + else + { + LLNotifications::instance().add(params); + } +} + +// static +void LLPanelEstateInfo::accessAddCore(U32 operation_flag, const std::string& dialog_name) +{ + LLSD payload; + payload["operation"] = (S32)operation_flag; + payload["dialog_name"] = dialog_name; + // agent id filled in after avatar picker + + LLNotification::Params params("ChangeLindenAccess"); + params.payload(payload) + .functor(accessAddCore2); + + if (isLindenEstate()) + { + LLNotifications::instance().add(params); + } + else + { + // same as clicking "OK" + LLNotifications::instance().forceResponse(params, 0); + } +} + +// static +bool LLPanelEstateInfo::accessAddCore2(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (option != 0) + { + // abort change + return false; + } + + LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo(notification["payload"]); + // avatar picker yes multi-select, yes close-on-select + LLFloaterAvatarPicker::show(accessAddCore3, (void*)change_info, TRUE, TRUE); + return false; +} + +// static +void LLPanelEstateInfo::accessAddCore3(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* data) +{ + LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data; + if (!change_info) return; + if (ids.empty()) + { + // User didn't select a name. + delete change_info; + change_info = NULL; + return; + } + // User did select a name. + change_info->mAgentOrGroupIDs = ids; + // Can't put estate owner on ban list + LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); + if (!panel) return; + LLViewerRegion* region = gAgent.getRegion(); + if (!region) return; + + if (change_info->mOperationFlag & ESTATE_ACCESS_ALLOWED_AGENT_ADD) + { + LLCtrlListInterface *list = panel->childGetListInterface("allowed_avatar_name_list"); + int currentCount = (list ? list->getItemCount() : 0); + if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS) + { + LLSD args; + args["NUM_ADDED"] = llformat("%d",ids.size()); + args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + args["LIST_TYPE"] = "Allowed Residents"; + args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); + LLNotifications::instance().add("MaxAgentOnRegionBatch", args); + delete change_info; + return; + } + } + if (change_info->mOperationFlag & ESTATE_ACCESS_BANNED_AGENT_ADD) + { + LLCtrlListInterface *list = panel->childGetListInterface("banned_avatar_name_list"); + int currentCount = (list ? list->getItemCount() : 0); + if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS) + { + LLSD args; + args["NUM_ADDED"] = llformat("%d",ids.size()); + args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + args["LIST_TYPE"] = "Banned Residents"; + args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); + LLNotifications::instance().add("MaxAgentOnRegionBatch", args); + delete change_info; + return; + } + } + + LLSD args; + args["ALL_ESTATES"] = all_estates_text(); + + LLNotification::Params params(change_info->mDialogName); + params.substitutions(args) + .payload(change_info->asLLSD()) + .functor(accessCoreConfirm); + + if (isLindenEstate()) + { + // just apply to this estate + LLNotifications::instance().forceResponse(params, 0); + } + else + { + // ask if this estate or all estates with this owner + LLNotifications::instance().add(params); + } +} + +// static +void LLPanelEstateInfo::accessRemoveCore(U32 operation_flag, const std::string& dialog_name, const std::string& list_ctrl_name) +{ + LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); + if (!panel) return; + LLNameListCtrl* name_list = panel->getChild<LLNameListCtrl>(list_ctrl_name); + if (!name_list) return; + + std::vector<LLScrollListItem*> list_vector = name_list->getAllSelected(); + if (list_vector.size() == 0) + return; + + LLSD payload; + payload["operation"] = (S32)operation_flag; + payload["dialog_name"] = dialog_name; + + for (std::vector<LLScrollListItem*>::const_iterator iter = list_vector.begin(); + iter != list_vector.end(); + iter++) + { + LLScrollListItem *item = (*iter); + payload["allowed_ids"].append(item->getUUID()); + } + + LLNotification::Params params("ChangeLindenAccess"); + params.payload(payload) + .functor(accessRemoveCore2); + + if (isLindenEstate()) + { + // warn on change linden estate + LLNotifications::instance().add(params); + } + else + { + // just proceed, as if clicking OK + LLNotifications::instance().forceResponse(params, 0); + } +} + +// static +bool LLPanelEstateInfo::accessRemoveCore2(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (option != 0) + { + // abort + return false; + } + + // If Linden estate, can only apply to "this" estate, not all estates + // owned by NULL. + if (isLindenEstate()) + { + accessCoreConfirm(notification, response); + } + else + { + LLSD args; + args["ALL_ESTATES"] = all_estates_text(); + LLNotifications::instance().add(notification["payload"]["dialog_name"], + args, + notification["payload"], + accessCoreConfirm); + } + return false; +} + +// Used for both access add and remove operations, depending on the mOperationFlag +// passed in (ESTATE_ACCESS_BANNED_AGENT_ADD, ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, etc.) +// static +bool LLPanelEstateInfo::accessCoreConfirm(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + const U32 originalFlags = (U32)notification["payload"]["operation"].asInteger(); + + LLViewerRegion* region = gAgent.getRegion(); + + LLSD::array_const_iterator end_it = notification["payload"]["allowed_ids"].endArray(); + + for (LLSD::array_const_iterator iter = notification["payload"]["allowed_ids"].beginArray(); + iter != end_it; + iter++) + { + U32 flags = originalFlags; + if (iter + 1 != end_it) + flags |= ESTATE_ACCESS_NO_REPLY; + + const LLUUID id = iter->asUUID(); + if (((U32)notification["payload"]["operation"].asInteger() & ESTATE_ACCESS_BANNED_AGENT_ADD) + && region && (region->getOwner() == id)) + { + LLNotifications::instance().add("OwnerCanNotBeDenied"); + break; + } + switch(option) + { + case 0: + // This estate + sendEstateAccessDelta(flags, id); + break; + case 1: + { + // All estates, either than I own or manage for this owner. + // This will be verified on simulator. JC + if (!region) break; + if (region->getOwner() == gAgent.getID() + || gAgent.isGodlike()) + { + flags |= ESTATE_ACCESS_APPLY_TO_ALL_ESTATES; + sendEstateAccessDelta(flags, id); + } + else if (region->isEstateManager()) + { + flags |= ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES; + sendEstateAccessDelta(flags, id); + } + break; + } + case 2: + default: + break; + } + } + return false; +} + +// key = "estateaccessdelta" +// str(estate_id) will be added to front of list by forward_EstateOwnerRequest_to_dataserver +// str[0] = str(agent_id) requesting the change +// str[1] = str(flags) (ESTATE_ACCESS_DELTA_*) +// str[2] = str(agent_id) to add or remove +// static +void LLPanelEstateInfo::sendEstateAccessDelta(U32 flags, const LLUUID& agent_or_group_id) +{ + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("EstateOwnerMessage"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used + + msg->nextBlock("MethodData"); + msg->addString("Method", "estateaccessdelta"); + msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice()); + + std::string buf; + gAgent.getID().toString(buf); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buf); + + buf = llformat("%u", flags); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buf); + + agent_or_group_id.toString(buf); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buf); + + + LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); + + if (flags & (ESTATE_ACCESS_ALLOWED_AGENT_ADD | ESTATE_ACCESS_ALLOWED_AGENT_REMOVE | + ESTATE_ACCESS_BANNED_AGENT_ADD | ESTATE_ACCESS_BANNED_AGENT_REMOVE)) + { + + panel->clearAccessLists(); + } + + gAgent.sendReliableMessage(); +} + +void LLPanelEstateInfo::updateControls(LLViewerRegion* region) +{ + BOOL god = gAgent.isGodlike(); + BOOL owner = (region && (region->getOwner() == gAgent.getID())); + BOOL manager = (region && region->isEstateManager()); + setCtrlsEnabled(god || owner || manager); + + childDisable("apply_btn"); + childSetEnabled("add_allowed_avatar_btn", god || owner || manager); + childSetEnabled("remove_allowed_avatar_btn", god || owner || manager); + childSetEnabled("add_allowed_group_btn", god || owner || manager); + childSetEnabled("remove_allowed_group_btn", god || owner || manager); + childSetEnabled("add_banned_avatar_btn", god || owner || manager); + childSetEnabled("remove_banned_avatar_btn", god || owner || manager); + childSetEnabled("message_estate_btn", god || owner || manager); + childSetEnabled("kick_user_from_estate_btn", god || owner || manager); + childSetEnabled("abuse_email_address", god || owner || manager); + + // estate managers can't add estate managers + childSetEnabled("add_estate_manager_btn", god || owner); + childSetEnabled("remove_estate_manager_btn", god || owner); + childSetEnabled("estate_manager_name_list", god || owner); +} + +bool LLPanelEstateInfo::refreshFromRegion(LLViewerRegion* region) +{ + updateControls(region); + + // let the parent class handle the general data collection. + bool rv = LLPanelRegionInfo::refreshFromRegion(region); + + // We want estate info. To make sure it works across region + // boundaries and multiple packets, we add a serial number to the + // integers and track against that on update. + strings_t strings; + //integers_t integers; + //LLFloaterRegionInfo::incrementSerial(); + LLFloaterRegionInfo::nextInvoice(); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + //integers.push_back(LLFloaterRegionInfo::());::getPanelEstate(); + + + LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); + panel->clearAccessLists(); + + + sendEstateOwnerMessage(gMessageSystem, "getinfo", invoice, strings); + + refresh(); + + return rv; +} + +void LLPanelEstateInfo::updateChild(LLUICtrl* child_ctrl) +{ + if (checkRemovalButton(child_ctrl->getName())) + { + // do nothing + } + else if (checkSunHourSlider(child_ctrl)) + { + // do nothing + } +} + +bool LLPanelEstateInfo::estateUpdate(LLMessageSystem* msg) +{ + llinfos << "LLPanelEstateInfo::estateUpdate()" << llendl; + return false; +} + + +BOOL LLPanelEstateInfo::postBuild() +{ + // set up the callbacks for the generic controls + initCtrl("externally_visible_check"); + initCtrl("use_global_time_check"); + initCtrl("fixed_sun_check"); + initCtrl("allow_direct_teleport"); + initCtrl("limit_payment"); + initCtrl("limit_age_verified"); + initCtrl("voice_chat_check"); + childSetCommitCallback("abuse_email_address", onChangeAnything, this); + childSetKeystrokeCallback("abuse_email_address", onChangeText, this); + + initHelpBtn("estate_manager_help", "HelpEstateEstateManager"); + initHelpBtn("use_global_time_help", "HelpEstateUseGlobalTime"); + initHelpBtn("fixed_sun_help", "HelpEstateFixedSun"); + initHelpBtn("WLEditSkyHelp", "HelpEditSky"); + initHelpBtn("WLEditDayCycleHelp", "HelpEditDayCycle"); + + initHelpBtn("externally_visible_help", "HelpEstateExternallyVisible"); + initHelpBtn("allow_direct_teleport_help", "HelpEstateAllowDirectTeleport"); + initHelpBtn("allow_resident_help", "HelpEstateAllowResident"); + initHelpBtn("allow_group_help", "HelpEstateAllowGroup"); + initHelpBtn("ban_resident_help", "HelpEstateBanResident"); + initHelpBtn("abuse_email_address_help", "HelpEstateAbuseEmailAddress"); + initHelpBtn("voice_chat_help", "HelpEstateVoiceChat"); + + // set up the use global time checkbox + childSetCommitCallback("use_global_time_check", onChangeUseGlobalTime, this); + childSetCommitCallback("fixed_sun_check", onChangeFixedSun, this); + childSetCommitCallback("sun_hour_slider", onChangeChildCtrl, this); + + childSetCommitCallback("allowed_avatar_name_list", onChangeChildCtrl, this); + LLNameListCtrl *avatar_name_list = getChild<LLNameListCtrl>("allowed_avatar_name_list"); + if (avatar_name_list) + { + avatar_name_list->setCommitOnSelectionChange(TRUE); + avatar_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); + } + + childSetAction("add_allowed_avatar_btn", onClickAddAllowedAgent, this); + childSetAction("remove_allowed_avatar_btn", onClickRemoveAllowedAgent, this); + + childSetCommitCallback("allowed_group_name_list", onChangeChildCtrl, this); + LLNameListCtrl* group_name_list = getChild<LLNameListCtrl>("allowed_group_name_list"); + if (group_name_list) + { + group_name_list->setCommitOnSelectionChange(TRUE); + group_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); + } + + childSetAction("add_allowed_group_btn", onClickAddAllowedGroup, this); + childSetAction("remove_allowed_group_btn", onClickRemoveAllowedGroup, this); + + childSetCommitCallback("banned_avatar_name_list", onChangeChildCtrl, this); + LLNameListCtrl* banned_name_list = getChild<LLNameListCtrl>("banned_avatar_name_list"); + if (banned_name_list) + { + banned_name_list->setCommitOnSelectionChange(TRUE); + banned_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); + } + + childSetAction("add_banned_avatar_btn", onClickAddBannedAgent, this); + childSetAction("remove_banned_avatar_btn", onClickRemoveBannedAgent, this); + + childSetCommitCallback("estate_manager_name_list", onChangeChildCtrl, this); + LLNameListCtrl* manager_name_list = getChild<LLNameListCtrl>("estate_manager_name_list"); + if (manager_name_list) + { + manager_name_list->setCommitOnSelectionChange(TRUE); + manager_name_list->setMaxItemCount(ESTATE_MAX_MANAGERS * 4); // Allow extras for dupe issue + } + + childSetAction("add_estate_manager_btn", onClickAddEstateManager, this); + childSetAction("remove_estate_manager_btn", onClickRemoveEstateManager, this); + childSetAction("message_estate_btn", onClickMessageEstate, this); + childSetAction("kick_user_from_estate_btn", onClickKickUser, this); + + childSetAction("WLEditSky", onClickEditSky, this); + childSetAction("WLEditDayCycle", onClickEditDayCycle, this); + + return LLPanelRegionInfo::postBuild(); +} + +void LLPanelEstateInfo::refresh() +{ + bool public_access = childGetValue("externally_visible_check").asBoolean(); + childSetEnabled("Only Allow", public_access); + childSetEnabled("limit_payment", public_access); + childSetEnabled("limit_age_verified", public_access); + // if this is set to false, then the limit fields are meaningless and should be turned off + if (public_access == false) + { + childSetValue("limit_payment", false); + childSetValue("limit_age_verified", false); + } +} + +BOOL LLPanelEstateInfo::sendUpdate() +{ + llinfos << "LLPanelEsateInfo::sendUpdate()" << llendl; + + LLNotification::Params params("ChangeLindenEstate"); + params.functor(boost::bind(&LLPanelEstateInfo::callbackChangeLindenEstate, this, _1, _2)); + + if (getEstateID() <= ESTATE_LAST_LINDEN) + { + // trying to change reserved estate, warn + LLNotifications::instance().add(params); + } + else + { + // for normal estates, just make the change + LLNotifications::instance().forceResponse(params, 0); + } + return TRUE; +} + +bool LLPanelEstateInfo::callbackChangeLindenEstate(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case 0: + // send the update + if (!commitEstateInfoCaps()) + { + // the caps method failed, try the old way + LLFloaterRegionInfo::nextInvoice(); + commitEstateInfoDataserver(); + } + // we don't want to do this because we'll get it automatically from the sim + // after the spaceserver processes it +// else +// { +// // caps method does not automatically send this info +// LLFloaterRegionInfo::requestRegionInfo(); +// } + break; + case 1: + default: + // do nothing + break; + } + return false; +} + + +/* +// Request = "getowner" +// SParam[0] = "" (empty string) +// IParam[0] = serial +void LLPanelEstateInfo::getEstateOwner() +{ + // TODO -- disable the panel + // and call this function whenever we cross a region boundary + // re-enable when owner matches, and get new estate info + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_EstateOwnerRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + + msg->nextBlockFast(_PREHASH_RequestData); + msg->addStringFast(_PREHASH_Request, "getowner"); + + // we send an empty string so that the variable block is not empty + msg->nextBlockFast(_PREHASH_StringData); + msg->addStringFast(_PREHASH_SParam, ""); + + msg->nextBlockFast(_PREHASH_IntegerData); + msg->addS32Fast(_PREHASH_IParam, LLFloaterRegionInfo::getSerial()); + + gAgent.sendMessage(); +} +*/ + +class LLEstateChangeInfoResponder : public LLHTTPClient::Responder +{ +public: + LLEstateChangeInfoResponder(void* userdata) : mpPanel((LLPanelEstateInfo*)userdata) {}; + + // if we get a normal response, handle it here + virtual void result(const LLSD& content) + { + // refresh the panel from the database + mpPanel->refresh(); + } + + // if we get an error response + virtual void error(U32 status, const std::string& reason) + { + llinfos << "LLEstateChangeInfoResponder::error " + << status << ": " << reason << llendl; + } +private: + LLPanelEstateInfo* mpPanel; +}; + +// tries to send estate info using a cap; returns true if it succeeded +bool LLPanelEstateInfo::commitEstateInfoCaps() +{ + std::string url = gAgent.getRegion()->getCapability("EstateChangeInfo"); + + if (url.empty()) + { + // whoops, couldn't find the cap, so bail out + return false; + } + + LLSD body; + body["estate_name"] = getEstateName(); + + body["is_externally_visible"] = childGetValue("externally_visible_check").asBoolean(); + body["allow_direct_teleport"] = childGetValue("allow_direct_teleport").asBoolean(); + body["is_sun_fixed" ] = childGetValue("fixed_sun_check").asBoolean(); + body["deny_anonymous" ] = childGetValue("limit_payment").asBoolean(); + body["deny_age_unverified" ] = childGetValue("limit_age_verified").asBoolean(); + body["allow_voice_chat" ] = childGetValue("voice_chat_check").asBoolean(); + body["invoice" ] = LLFloaterRegionInfo::getLastInvoice(); + + // block fly is in estate database but not in estate UI, so we're not supporting it + //body["block_fly" ] = childGetValue("").asBoolean(); + + F32 sun_hour = getSunHour(); + if (childGetValue("use_global_time_check").asBoolean()) + { + sun_hour = 0.f; // 0 = global time + } + body["sun_hour"] = sun_hour; + + body["owner_abuse_email"] = childGetValue("abuse_email_address").asString(); + + // we use a responder so that we can re-get the data after committing to the database + LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder((void*)this)); + return true; +} + +/* This is the old way of doing things, is deprecated, and should be + deleted when the dataserver model can be removed */ +// key = "estatechangeinfo" +// strings[0] = str(estate_id) (added by simulator before relay - not here) +// strings[1] = estate_name +// strings[2] = str(estate_flags) +// strings[3] = str((S32)(sun_hour * 1024.f)) +void LLPanelEstateInfo::commitEstateInfoDataserver() +{ + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("EstateOwnerMessage"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used + + msg->nextBlock("MethodData"); + msg->addString("Method", "estatechangeinfo"); + msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice()); + + msg->nextBlock("ParamList"); + msg->addString("Parameter", getEstateName()); + + std::string buffer; + buffer = llformat("%u", computeEstateFlags()); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + + F32 sun_hour = getSunHour(); + if (childGetValue("use_global_time_check").asBoolean()) + { + sun_hour = 0.f; // 0 = global time + } + + buffer = llformat("%d", (S32)(sun_hour*1024.0f)); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buffer); + + gAgent.sendMessage(); +} + +void LLPanelEstateInfo::setEstateFlags(U32 flags) +{ + childSetValue("externally_visible_check", LLSD(flags & REGION_FLAGS_EXTERNALLY_VISIBLE ? TRUE : FALSE) ); + childSetValue("fixed_sun_check", LLSD(flags & REGION_FLAGS_SUN_FIXED ? TRUE : FALSE) ); + childSetValue( + "voice_chat_check", + LLSD(flags & REGION_FLAGS_ALLOW_VOICE ? TRUE : FALSE)); + childSetValue("allow_direct_teleport", LLSD(flags & REGION_FLAGS_ALLOW_DIRECT_TELEPORT ? TRUE : FALSE) ); + childSetValue("limit_payment", LLSD(flags & REGION_FLAGS_DENY_ANONYMOUS ? TRUE : FALSE) ); + childSetValue("limit_age_verified", LLSD(flags & REGION_FLAGS_DENY_AGEUNVERIFIED ? TRUE : FALSE) ); + + refresh(); +} + +U32 LLPanelEstateInfo::computeEstateFlags() +{ + U32 flags = 0; + + if (childGetValue("externally_visible_check").asBoolean()) + { + flags |= REGION_FLAGS_EXTERNALLY_VISIBLE; + } + + if ( childGetValue("voice_chat_check").asBoolean() ) + { + flags |= REGION_FLAGS_ALLOW_VOICE; + } + + if (childGetValue("allow_direct_teleport").asBoolean()) + { + flags |= REGION_FLAGS_ALLOW_DIRECT_TELEPORT; + } + + if (childGetValue("fixed_sun_check").asBoolean()) + { + flags |= REGION_FLAGS_SUN_FIXED; + } + + if (childGetValue("limit_payment").asBoolean()) + { + flags |= REGION_FLAGS_DENY_ANONYMOUS; + } + + if (childGetValue("limit_age_verified").asBoolean()) + { + flags |= REGION_FLAGS_DENY_AGEUNVERIFIED; + } + + + return flags; +} + +BOOL LLPanelEstateInfo::getGlobalTime() +{ + return childGetValue("use_global_time_check").asBoolean(); +} + +void LLPanelEstateInfo::setGlobalTime(bool b) +{ + childSetValue("use_global_time_check", LLSD(b)); + childSetEnabled("fixed_sun_check", LLSD(!b)); + childSetEnabled("sun_hour_slider", LLSD(!b)); + if (b) + { + childSetValue("sun_hour_slider", LLSD(0.f)); + } +} + + +BOOL LLPanelEstateInfo::getFixedSun() +{ + return childGetValue("fixed_sun_check").asBoolean(); +} + +void LLPanelEstateInfo::setSunHour(F32 sun_hour) +{ + if(sun_hour < 6.0f) + { + sun_hour = 24.0f + sun_hour; + } + childSetValue("sun_hour_slider", LLSD(sun_hour)); +} + +F32 LLPanelEstateInfo::getSunHour() +{ + if (childIsEnabled("sun_hour_slider")) + { + return (F32)childGetValue("sun_hour_slider").asReal(); + } + return 0.f; +} + +const std::string LLPanelEstateInfo::getEstateName() const +{ + return childGetValue("estate_name").asString(); +} + +void LLPanelEstateInfo::setEstateName(const std::string& name) +{ + childSetValue("estate_name", LLSD(name)); +} + +const std::string LLPanelEstateInfo::getOwnerName() const +{ + return childGetValue("estate_owner").asString(); +} + +void LLPanelEstateInfo::setOwnerName(const std::string& name) +{ + childSetValue("estate_owner", LLSD(name)); +} + +const std::string LLPanelEstateInfo::getAbuseEmailAddress() const +{ + return childGetValue("abuse_email_address").asString(); +} + +void LLPanelEstateInfo::setAbuseEmailAddress(const std::string& address) +{ + childSetValue("abuse_email_address", LLSD(address)); +} + +void LLPanelEstateInfo::setAccessAllowedEnabled(bool enable_agent, + bool enable_group, + bool enable_ban) +{ + childSetEnabled("allow_resident_label", enable_agent); + childSetEnabled("allowed_avatar_name_list", enable_agent); + childSetVisible("allowed_avatar_name_list", enable_agent); + childSetEnabled("add_allowed_avatar_btn", enable_agent); + childSetEnabled("remove_allowed_avatar_btn", enable_agent); + + // Groups + childSetEnabled("allow_group_label", enable_group); + childSetEnabled("allowed_group_name_list", enable_group); + childSetVisible("allowed_group_name_list", enable_group); + childSetEnabled("add_allowed_group_btn", enable_group); + childSetEnabled("remove_allowed_group_btn", enable_group); + + // Ban + childSetEnabled("ban_resident_label", enable_ban); + childSetEnabled("banned_avatar_name_list", enable_ban); + childSetVisible("banned_avatar_name_list", enable_ban); + childSetEnabled("add_banned_avatar_btn", enable_ban); + childSetEnabled("remove_banned_avatar_btn", enable_ban); + + // Update removal buttons if needed + if (enable_agent) + { + checkRemovalButton("allowed_avatar_name_list"); + } + + if (enable_group) + { + checkRemovalButton("allowed_group_name_list"); + } + + if (enable_ban) + { + checkRemovalButton("banned_avatar_name_list"); + } +} + +// static +void LLPanelEstateInfo::callbackCacheName( + const LLUUID& id, + const std::string& first, + const std::string& last, + BOOL is_group, + void*) +{ + LLPanelEstateInfo* self = LLFloaterRegionInfo::getPanelEstate(); + if (!self) return; + + std::string name; + + if (id.isNull()) + { + name = "(none)"; + } + else + { + name = first + " " + last; + } + + self->setOwnerName(name); +} + +void LLPanelEstateInfo::clearAccessLists() +{ + LLNameListCtrl* name_list = getChild<LLNameListCtrl>("allowed_avatar_name_list"); + if (name_list) + { + name_list->deleteAllItems(); + } + + name_list = getChild<LLNameListCtrl>("banned_avatar_name_list"); + if (name_list) + { + name_list->deleteAllItems(); + } +} + +// enables/disables the "remove" button for the various allow/ban lists +BOOL LLPanelEstateInfo::checkRemovalButton(std::string name) +{ + std::string btn_name = ""; + if (name == "allowed_avatar_name_list") + { + btn_name = "remove_allowed_avatar_btn"; + } + else if (name == "allowed_group_name_list") + { + btn_name = "remove_allowed_group_btn"; + } + else if (name == "banned_avatar_name_list") + { + btn_name = "remove_banned_avatar_btn"; + } + else if (name == "estate_manager_name_list") + { + //ONLY OWNER CAN ADD /DELET ESTATE MANAGER + LLViewerRegion* region = gAgent.getRegion(); + if (region && (region->getOwner() == gAgent.getID())) + { + btn_name = "remove_estate_manager_btn"; + } + } + + // enable the remove button if something is selected + LLNameListCtrl* name_list = getChild<LLNameListCtrl>(name); + childSetEnabled(btn_name, name_list && name_list->getFirstSelected() ? TRUE : FALSE); + + return (btn_name != ""); +} + +BOOL LLPanelEstateInfo::checkSunHourSlider(LLUICtrl* child_ctrl) +{ + BOOL found_child_ctrl = FALSE; + if (child_ctrl->getName() == "sun_hour_slider") + { + enableButton("apply_btn"); + found_child_ctrl = TRUE; + } + return found_child_ctrl; +} + +// static +void LLPanelEstateInfo::onClickMessageEstate(void* userdata) +{ + llinfos << "LLPanelEstateInfo::onClickMessageEstate" << llendl; + LLNotifications::instance().add("MessageEstate", LLSD(), LLSD(), boost::bind(&LLPanelEstateInfo::onMessageCommit, (LLPanelEstateInfo*)userdata, _1, _2)); +} + +bool LLPanelEstateInfo::onMessageCommit(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + std::string text = response["message"].asString(); + if(option != 0) return false; + if(text.empty()) return false; + llinfos << "Message to everyone: " << text << llendl; + strings_t strings; + //integers_t integers; + std::string name; + gAgent.buildFullname(name); + strings.push_back(strings_t::value_type(name)); + strings.push_back(strings_t::value_type(text)); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + sendEstateOwnerMessage(gMessageSystem, "instantmessage", invoice, strings); + return false; +} + +LLPanelEstateCovenant::LLPanelEstateCovenant() +: mCovenantID(LLUUID::null) +{ +} + +// virtual +bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region) +{ + LLTextBox* region_name = getChild<LLTextBox>("region_name_text"); + if (region_name) + { + region_name->setText(region->getName()); + } + + LLTextBox* resellable_clause = getChild<LLTextBox>("resellable_clause"); + if (resellable_clause) + { + if (region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL) + { + resellable_clause->setText(getString("can_not_resell")); + } + else + { + resellable_clause->setText(getString("can_resell")); + } + } + + LLTextBox* changeable_clause = getChild<LLTextBox>("changeable_clause"); + if (changeable_clause) + { + if (region->getRegionFlags() & REGION_FLAGS_ALLOW_PARCEL_CHANGES) + { + changeable_clause->setText(getString("can_change")); + } + else + { + changeable_clause->setText(getString("can_not_change")); + } + } + + LLTextBox* region_maturity = getChild<LLTextBox>("region_maturity_text"); + if (region_maturity) + { + region_maturity->setText(region->getSimAccessString()); + } + + LLTextBox* region_landtype = getChild<LLTextBox>("region_landtype_text"); + if (region_landtype) + { + region_landtype->setText(region->getSimProductName()); + } + + + // let the parent class handle the general data collection. + bool rv = LLPanelRegionInfo::refreshFromRegion(region); + LLMessageSystem *msg = gMessageSystem; + msg->newMessage("EstateCovenantRequest"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); + msg->sendReliable(region->getHost()); + return rv; +} + +// virtual +bool LLPanelEstateCovenant::estateUpdate(LLMessageSystem* msg) +{ + llinfos << "LLPanelEstateCovenant::estateUpdate()" << llendl; + return true; +} + +// virtual +BOOL LLPanelEstateCovenant::postBuild() +{ + initHelpBtn("covenant_help", "HelpEstateCovenant"); + mEstateNameText = getChild<LLTextBox>("estate_name_text"); + mEstateOwnerText = getChild<LLTextBox>("estate_owner_text"); + mLastModifiedText = getChild<LLTextBox>("covenant_timestamp_text"); + mEditor = getChild<LLViewerTextEditor>("covenant_editor"); + if (mEditor) mEditor->setHandleEditKeysDirectly(TRUE); + LLButton* reset_button = getChild<LLButton>("reset_covenant"); + reset_button->setEnabled(gAgent.canManageEstate()); + reset_button->setClickedCallback(LLPanelEstateCovenant::resetCovenantID, NULL); + + return LLPanelRegionInfo::postBuild(); +} + +// virtual +void LLPanelEstateCovenant::updateChild(LLUICtrl* child_ctrl) +{ +} + +// virtual +BOOL LLPanelEstateCovenant::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + LLInventoryItem* item = (LLInventoryItem*)cargo_data; + + if (!gAgent.canManageEstate()) + { + *accept = ACCEPT_NO; + return TRUE; + } + + switch(cargo_type) + { + case DAD_NOTECARD: + *accept = ACCEPT_YES_COPY_SINGLE; + if (item && drop) + { + LLSD payload; + payload["item_id"] = item->getUUID(); + LLNotifications::instance().add("EstateChangeCovenant", LLSD(), payload, + LLPanelEstateCovenant::confirmChangeCovenantCallback); + } + break; + default: + *accept = ACCEPT_NO; + break; + } + + return TRUE; +} + +// static +bool LLPanelEstateCovenant::confirmChangeCovenantCallback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + LLInventoryItem* item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); + LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant(); + + if (!item || !self) return false; + + switch(option) + { + case 0: + self->loadInvItem(item); + break; + default: + break; + } + return false; +} + +// static +void LLPanelEstateCovenant::resetCovenantID(void* userdata) +{ + LLNotifications::instance().add("EstateChangeCovenant", LLSD(), LLSD(), confirmResetCovenantCallback); +} + +// static +bool LLPanelEstateCovenant::confirmResetCovenantCallback(const LLSD& notification, const LLSD& response) +{ + LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant(); + if (!self) return false; + + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case 0: + self->loadInvItem(NULL); + break; + default: + break; + } + return false; +} + +void LLPanelEstateCovenant::loadInvItem(LLInventoryItem *itemp) +{ + const BOOL high_priority = TRUE; + if (itemp) + { + gAssetStorage->getInvItemAsset(gAgent.getRegionHost(), + gAgent.getID(), + gAgent.getSessionID(), + itemp->getPermissions().getOwner(), + LLUUID::null, + itemp->getUUID(), + itemp->getAssetUUID(), + itemp->getType(), + onLoadComplete, + (void*)this, + high_priority); + mAssetStatus = ASSET_LOADING; + } + else + { + mAssetStatus = ASSET_LOADED; + setCovenantTextEditor("There is no Covenant provided for this Estate."); + sendChangeCovenantID(LLUUID::null); + } +} + +// static +void LLPanelEstateCovenant::onLoadComplete(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + llinfos << "LLPanelEstateCovenant::onLoadComplete()" << llendl; + LLPanelEstateCovenant* panelp = (LLPanelEstateCovenant*)user_data; + if( panelp ) + { + if(0 == status) + { + LLVFile file(vfs, asset_uuid, type, LLVFile::READ); + + S32 file_length = file.getSize(); + + char* buffer = new char[file_length+1]; + if (buffer == NULL) + { + llerrs << "Memory Allocation Failed" << llendl; + return; + } + + file.read((U8*)buffer, file_length); /* Flawfinder: ignore */ + // put a EOS at the end + buffer[file_length] = 0; + + if( (file_length > 19) && !strncmp( buffer, "Linden text version", 19 ) ) + { + if( !panelp->mEditor->importBuffer( buffer, file_length+1 ) ) + { + llwarns << "Problem importing estate covenant." << llendl; + LLNotifications::instance().add("ProblemImportingEstateCovenant"); + } + else + { + panelp->sendChangeCovenantID(asset_uuid); + } + } + else + { + // Version 0 (just text, doesn't include version number) + panelp->sendChangeCovenantID(asset_uuid); + } + delete[] buffer; + } + else + { + LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED ); + + if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || + LL_ERR_FILE_EMPTY == status) + { + LLNotifications::instance().add("MissingNotecardAssetID"); + } + else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) + { + LLNotifications::instance().add("NotAllowedToViewNotecard"); + } + else + { + LLNotifications::instance().add("UnableToLoadNotecardAsset"); + } + + llwarns << "Problem loading notecard: " << status << llendl; + } + panelp->mAssetStatus = ASSET_LOADED; + panelp->setCovenantID(asset_uuid); + } +} + +// key = "estatechangecovenantid" +// strings[0] = str(estate_id) (added by simulator before relay - not here) +// strings[1] = str(covenant_id) +void LLPanelEstateCovenant::sendChangeCovenantID(const LLUUID &asset_id) +{ + if (asset_id != getCovenantID()) + { + setCovenantID(asset_id); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("EstateOwnerMessage"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used + + msg->nextBlock("MethodData"); + msg->addString("Method", "estatechangecovenantid"); + msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice()); + + msg->nextBlock("ParamList"); + msg->addString("Parameter", getCovenantID().asString()); + gAgent.sendReliableMessage(); + } +} + +// virtual +BOOL LLPanelEstateCovenant::sendUpdate() +{ + return TRUE; +} + +const std::string& LLPanelEstateCovenant::getEstateName() const +{ + return mEstateNameText->getText(); +} + +void LLPanelEstateCovenant::setEstateName(const std::string& name) +{ + mEstateNameText->setText(name); +} + +// static +void LLPanelEstateCovenant::updateCovenantText(const std::string& string, const LLUUID& asset_id) +{ + LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); + if( panelp ) + { + panelp->mEditor->setText(string); + panelp->setCovenantID(asset_id); + } +} + +// static +void LLPanelEstateCovenant::updateEstateName(const std::string& name) +{ + LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); + if( panelp ) + { + panelp->mEstateNameText->setText(name); + } +} + +// static +void LLPanelEstateCovenant::updateLastModified(const std::string& text) +{ + LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); + if( panelp ) + { + panelp->mLastModifiedText->setText(text); + } +} + +// static +void LLPanelEstateCovenant::updateEstateOwnerName(const std::string& name) +{ + LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); + if( panelp ) + { + panelp->mEstateOwnerText->setText(name); + } +} + +const std::string& LLPanelEstateCovenant::getOwnerName() const +{ + return mEstateOwnerText->getText(); +} + +void LLPanelEstateCovenant::setOwnerName(const std::string& name) +{ + mEstateOwnerText->setText(name); +} + +void LLPanelEstateCovenant::setCovenantTextEditor(const std::string& text) +{ + mEditor->setText(text); +} + +// key = "estateupdateinfo" +// strings[0] = estate name +// strings[1] = str(owner_id) +// strings[2] = str(estate_id) +// strings[3] = str(estate_flags) +// strings[4] = str((S32)(sun_hour * 1024)) +// strings[5] = str(parent_estate_id) +// strings[6] = str(covenant_id) +// strings[7] = str(covenant_timestamp) +// strings[8] = str(send_to_agent_only) +// strings[9] = str(abuse_email_addr) +bool LLDispatchEstateUpdateInfo::operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) +{ + LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); + if (!panel) return true; + + // NOTE: LLDispatcher extracts strings with an extra \0 at the + // end. If we pass the std::string direct to the UI/renderer + // it draws with a weird character at the end of the string. + std::string estate_name = strings[0].c_str(); // preserve c_str() call! + panel->setEstateName(estate_name); + + if (strings.size() > 3) + { + std::string abuse_email = strings[9].c_str(); // preserve c_str() call! + panel->setAbuseEmailAddress(abuse_email); + } + else + { + panel->setAbuseEmailAddress(panel->getString("email_unsupported")); + } + + LLViewerRegion* regionp = gAgent.getRegion(); + + LLUUID owner_id(strings[1]); + regionp->setOwner(owner_id); + // Update estate owner name in UI + const BOOL is_group = FALSE; + gCacheName->get(owner_id, is_group, LLPanelEstateInfo::callbackCacheName); + + U32 estate_id = strtoul(strings[2].c_str(), NULL, 10); + panel->setEstateID(estate_id); + + U32 flags = strtoul(strings[3].c_str(), NULL, 10); + panel->setEstateFlags(flags); + + F32 sun_hour = ((F32)(strtod(strings[4].c_str(), NULL)))/1024.0f; + if(sun_hour == 0 && (flags & REGION_FLAGS_SUN_FIXED ? FALSE : TRUE)) + { + panel->setGlobalTime(TRUE); + } + else + { + panel->setGlobalTime(FALSE); + panel->setSunHour(sun_hour); + } + + bool visible_from_mainland = (bool)(flags & REGION_FLAGS_EXTERNALLY_VISIBLE); + bool god = gAgent.isGodlike(); + bool linden_estate = (estate_id <= ESTATE_LAST_LINDEN); + + // If visible from mainland, disable the access allowed + // UI, as anyone can teleport there. + // However, gods need to be able to edit the access list for + // linden estates, regardless of visibility, to allow object + // and L$ transfers. + bool enable_agent = (!visible_from_mainland || (god && linden_estate)); + bool enable_group = enable_agent; + bool enable_ban = !linden_estate; + panel->setAccessAllowedEnabled(enable_agent, enable_group, enable_ban); + + return true; +} + + +// key = "setaccess" +// strings[0] = str(estate_id) +// strings[1] = str(packed_access_lists) +// strings[2] = str(num allowed agent ids) +// strings[3] = str(num allowed group ids) +// strings[4] = str(num banned agent ids) +// strings[5] = str(num estate manager agent ids) +// strings[6] = bin(uuid) +// strings[7] = bin(uuid) +// strings[8] = bin(uuid) +// ... +bool LLDispatchSetEstateAccess::operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) +{ + LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); + if (!panel) return true; + + S32 index = 1; // skip estate_id + U32 access_flags = strtoul(strings[index++].c_str(), NULL,10); + S32 num_allowed_agents = strtol(strings[index++].c_str(), NULL, 10); + S32 num_allowed_groups = strtol(strings[index++].c_str(), NULL, 10); + S32 num_banned_agents = strtol(strings[index++].c_str(), NULL, 10); + S32 num_estate_managers = strtol(strings[index++].c_str(), NULL, 10); + + // sanity ckecks + if (num_allowed_agents > 0 + && !(access_flags & ESTATE_ACCESS_ALLOWED_AGENTS)) + { + llwarns << "non-zero count for allowed agents, but no corresponding flag" << llendl; + } + if (num_allowed_groups > 0 + && !(access_flags & ESTATE_ACCESS_ALLOWED_GROUPS)) + { + llwarns << "non-zero count for allowed groups, but no corresponding flag" << llendl; + } + if (num_banned_agents > 0 + && !(access_flags & ESTATE_ACCESS_BANNED_AGENTS)) + { + llwarns << "non-zero count for banned agents, but no corresponding flag" << llendl; + } + if (num_estate_managers > 0 + && !(access_flags & ESTATE_ACCESS_MANAGERS)) + { + llwarns << "non-zero count for managers, but no corresponding flag" << llendl; + } + + // grab the UUID's out of the string fields + if (access_flags & ESTATE_ACCESS_ALLOWED_AGENTS) + { + LLNameListCtrl* allowed_agent_name_list; + allowed_agent_name_list = panel->getChild<LLNameListCtrl>("allowed_avatar_name_list"); + + int totalAllowedAgents = num_allowed_agents; + + if (allowed_agent_name_list) + { + totalAllowedAgents += allowed_agent_name_list->getItemCount(); + } + + std::string msg = llformat("Allowed residents: (%d, max %d)", + totalAllowedAgents, + ESTATE_MAX_ACCESS_IDS); + panel->childSetValue("allow_resident_label", LLSD(msg)); + + if (allowed_agent_name_list) + { + //allowed_agent_name_list->deleteAllItems(); + for (S32 i = 0; i < num_allowed_agents && i < ESTATE_MAX_ACCESS_IDS; i++) + { + LLUUID id; + memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ + allowed_agent_name_list->addNameItem(id); + } + panel->childSetEnabled("remove_allowed_avatar_btn", allowed_agent_name_list->getFirstSelected() ? TRUE : FALSE); + allowed_agent_name_list->sortByColumnIndex(0, TRUE); + } + } + + if (access_flags & ESTATE_ACCESS_ALLOWED_GROUPS) + { + LLNameListCtrl* allowed_group_name_list; + allowed_group_name_list = panel->getChild<LLNameListCtrl>("allowed_group_name_list"); + + std::string msg = llformat("Allowed groups: (%d, max %d)", + num_allowed_groups, + (S32) ESTATE_MAX_GROUP_IDS); + panel->childSetValue("allow_group_label", LLSD(msg)); + + if (allowed_group_name_list) + { + allowed_group_name_list->deleteAllItems(); + for (S32 i = 0; i < num_allowed_groups && i < ESTATE_MAX_GROUP_IDS; i++) + { + LLUUID id; + memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ + allowed_group_name_list->addGroupNameItem(id); + } + panel->childSetEnabled("remove_allowed_group_btn", allowed_group_name_list->getFirstSelected() ? TRUE : FALSE); + allowed_group_name_list->sortByColumnIndex(0, TRUE); + } + } + + if (access_flags & ESTATE_ACCESS_BANNED_AGENTS) + { + LLNameListCtrl* banned_agent_name_list; + banned_agent_name_list = panel->getChild<LLNameListCtrl>("banned_avatar_name_list"); + + int totalBannedAgents = num_banned_agents; + + if (banned_agent_name_list) + { + totalBannedAgents += banned_agent_name_list->getItemCount(); + } + + + std::string msg = llformat("Banned residents: (%d, max %d)", + totalBannedAgents, + ESTATE_MAX_ACCESS_IDS); + panel->childSetValue("ban_resident_label", LLSD(msg)); + + if (banned_agent_name_list) + { + //banned_agent_name_list->deleteAllItems(); + for (S32 i = 0; i < num_banned_agents && i < ESTATE_MAX_ACCESS_IDS; i++) + { + LLUUID id; + memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ + banned_agent_name_list->addNameItem(id); + } + panel->childSetEnabled("remove_banned_avatar_btn", banned_agent_name_list->getFirstSelected() ? TRUE : FALSE); + banned_agent_name_list->sortByColumnIndex(0, TRUE); + } + } + + if (access_flags & ESTATE_ACCESS_MANAGERS) + { + std::string msg = llformat("Estate Managers: (%d, max %d)", + num_estate_managers, + ESTATE_MAX_MANAGERS); + panel->childSetValue("estate_manager_label", LLSD(msg)); + + LLNameListCtrl* estate_manager_name_list = + panel->getChild<LLNameListCtrl>("estate_manager_name_list"); + if (estate_manager_name_list) + { + estate_manager_name_list->deleteAllItems(); // Clear existing entries + + // There should be only ESTATE_MAX_MANAGERS people in the list, but if the database gets more (SL-46107) don't + // truncate the list unless it's really big. Go ahead and show the extras so the user doesn't get confused, + // and they can still remove them. + for (S32 i = 0; i < num_estate_managers && i < (ESTATE_MAX_MANAGERS * 4); i++) + { + LLUUID id; + memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ + estate_manager_name_list->addNameItem(id); + } + panel->childSetEnabled("remove_estate_manager_btn", estate_manager_name_list->getFirstSelected() ? TRUE : FALSE); + estate_manager_name_list->sortByColumnIndex(0, TRUE); + } + } + + return true; +} + +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) +void LLFloaterRegionInfo::open() +{ + // We'll allow access to the estate tools for estate managers (and for the sim owner) + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + LLViewerRegion* pRegion = gAgent.getRegion(); + if (!pRegion) + return; + + // Should be able to call LLRegion::canManageEstate() but then we can fake god like + if ( (!pRegion->isEstateManager()) && (pRegion->getOwner() != gAgent.getID()) ) + return; + } + + LLFloater::open(); +} +// [/RLVa:KB] diff --git a/linden/indra/newview/llfloaterregioninfo.h b/linden/indra/newview/llfloaterregioninfo.h index fd0d9ce63..ae0c99360 100644 --- a/linden/indra/newview/llfloaterregioninfo.h +++ b/linden/indra/newview/llfloaterregioninfo.h @@ -53,6 +53,7 @@ class LLSpinCtrl; class LLTextBox; class LLPanelRegionGeneralInfo; +class LLPanelRegionOpenSettingsInfo; class LLPanelRegionDebugInfo; class LLPanelRegionTextureInfo; class LLPanelRegionTerrainInfo; @@ -83,6 +84,7 @@ class LLFloaterRegionInfo : public LLFloater, public LLFloaterSingleton<LLFloate static LLPanelEstateInfo* getPanelEstate(); static LLPanelEstateCovenant* getPanelCovenant(); + static LLPanelRegionOpenSettingsInfo* getPanelOpenSettings(); // from LLPanel virtual void refresh(); @@ -173,6 +175,24 @@ class LLPanelRegionGeneralInfo : public LLPanelRegionInfo ///////////////////////////////////////////////////////////////////////////// +class LLPanelRegionOpenSettingsInfo : public LLPanelRegionInfo +{ +public: + LLPanelRegionOpenSettingsInfo() + : LLPanelRegionInfo() {} + ~LLPanelRegionOpenSettingsInfo() {} + + virtual bool refreshFromRegion(LLViewerRegion* region); + + // LLPanel + virtual BOOL postBuild(); + +protected: + static void onClickOrs(void* userdata); +}; + +///////////////////////////////////////////////////////////////////////////// + class LLPanelRegionDebugInfo : public LLPanelRegionInfo { public: diff --git a/linden/indra/newview/llfloatersellland.cpp b/linden/indra/newview/llfloatersellland.cpp index bf4a4c3c9..9b257089f 100644 --- a/linden/indra/newview/llfloatersellland.cpp +++ b/linden/indra/newview/llfloatersellland.cpp @@ -46,7 +46,7 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // defined in llfloaterland.cpp void send_parcel_select_objects(S32 parcel_local_id, S32 return_type, diff --git a/linden/indra/newview/llfloatersnapshot.cpp b/linden/indra/newview/llfloatersnapshot.cpp index c0e972d6e..e007680fa 100644 --- a/linden/indra/newview/llfloatersnapshot.cpp +++ b/linden/indra/newview/llfloatersnapshot.cpp @@ -77,7 +77,7 @@ #include "llvfile.h" #include "llvfs.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -2128,7 +2128,6 @@ BOOL LLFloaterSnapshot::postBuild() //gSnapshotFloaterView->addChild(this); impl.updateControls(this); - impl.updateLayout(this); return TRUE; } diff --git a/linden/indra/newview/llfloatertools.cpp b/linden/indra/newview/llfloatertools.cpp index fc72467c7..0cb35e3ff 100644 --- a/linden/indra/newview/llfloatertools.cpp +++ b/linden/indra/newview/llfloatertools.cpp @@ -84,8 +84,8 @@ #include "llvograss.h" #include "llvotree.h" #include "lluictrlfactory.h" - -#include "hippoLimits.h" +#include "qtoolalign.h" +#include "hippolimits.h" // Globals LLFloaterTools *gFloaterTools = NULL; @@ -181,26 +181,23 @@ void* LLFloaterTools::createPanelLandInfo(void* data) void LLFloaterTools::updateToolsSizeLimits() { - if (gSavedSettings.getBOOL("DisableMaxBuildConstraints")) - { - getChild<LLSpinCtrl>("Scale X")->setMaxValue(F32_MAX); - getChild<LLSpinCtrl>("Scale Y")->setMaxValue(F32_MAX); - getChild<LLSpinCtrl>("Scale Z")->setMaxValue(F32_MAX); + getChild<LLSpinCtrl>("Scale X")->setMinValue(gHippoLimits->getMinPrimScale()); + getChild<LLSpinCtrl>("Scale Y")->setMinValue(gHippoLimits->getMinPrimScale()); + getChild<LLSpinCtrl>("Scale Z")->setMinValue(gHippoLimits->getMinPrimScale()); - getChild<LLSpinCtrl>("Pos X")->setMaxValue(F32_MAX); - getChild<LLSpinCtrl>("Pos Y")->setMaxValue(F32_MAX); - getChild<LLSpinCtrl>("Pos Z")->setMaxValue(F32_MAX); - } - else - { - getChild<LLSpinCtrl>("Scale X")->setMaxValue(gHippoLimits->getMaxPrimScale()); - getChild<LLSpinCtrl>("Scale Y")->setMaxValue(gHippoLimits->getMaxPrimScale()); - getChild<LLSpinCtrl>("Scale Z")->setMaxValue(gHippoLimits->getMaxPrimScale()); + getChild<LLSpinCtrl>("Scale X")->setMaxValue(gHippoLimits->getMaxPrimScale()); + getChild<LLSpinCtrl>("Scale Y")->setMaxValue(gHippoLimits->getMaxPrimScale()); + getChild<LLSpinCtrl>("Scale Z")->setMaxValue(gHippoLimits->getMaxPrimScale()); - getChild<LLSpinCtrl>("Scale X")->setMinValue(gHippoLimits->getMinPrimScale()); - getChild<LLSpinCtrl>("Scale Y")->setMinValue(gHippoLimits->getMinPrimScale()); - getChild<LLSpinCtrl>("Scale Z")->setMinValue(gHippoLimits->getMinPrimScale()); - } + getChild<LLSpinCtrl>("Pos X")->setMinValue(gHippoLimits->getMinPrimXPos()); + getChild<LLSpinCtrl>("Pos Y")->setMinValue(gHippoLimits->getMinPrimYPos()); + getChild<LLSpinCtrl>("Pos Z")->setMinValue(gHippoLimits->getMinPrimZPos()); + + getChild<LLSpinCtrl>("Pos X")->setMaxValue(gHippoLimits->getMaxPrimXPos()); + getChild<LLSpinCtrl>("Pos Y")->setMaxValue(gHippoLimits->getMaxPrimYPos()); + getChild<LLSpinCtrl>("Pos Z")->setMaxValue(gHippoLimits->getMaxPrimZPos()); + + getChild<LLCheckBoxCtrl>("Physical Checkbox Ctrl")->setEnabled(gHippoLimits->mAllowPhysicalPrims); } void LLFloaterTools::updateToolsPrecision() @@ -273,6 +270,8 @@ BOOL LLFloaterTools::postBuild() childSetCommitCallback("radio stretch",commit_select_tool,LLToolCompScale::getInstance()); mRadioSelectFace = getChild<LLCheckBoxCtrl>("radio select face"); childSetCommitCallback("radio select face",commit_select_tool,LLToolFace::getInstance()); + mRadioAlign = getChild<LLCheckBoxCtrl>("radio align"); + childSetCommitCallback("radio align",commit_select_tool,QToolAlign::getInstance()); mCheckSelectIndividual = getChild<LLCheckBoxCtrl>("checkbox edit linked parts"); childSetValue("checkbox edit linked parts",(BOOL)gSavedSettings.getBOOL("EditLinkedParts")); childSetCommitCallback("checkbox edit linked parts",commit_select_component,this); @@ -394,6 +393,7 @@ BOOL LLFloaterTools::postBuild() mStatusText["rotate"] = getString("status_rotate"); mStatusText["scale"] = getString("status_scale"); mStatusText["move"] = getString("status_move"); + mStatusText["align"] = getString("status_align"); mStatusText["modifyland"] = getString("status_modifyland"); mStatusText["camera"] = getString("status_camera"); mStatusText["grab"] = getString("status_grab"); @@ -426,6 +426,7 @@ LLFloaterTools::LLFloaterTools() mRadioRotate(NULL), mRadioStretch(NULL), mRadioSelectFace(NULL), + mRadioAlign(NULL), mCheckSelectIndividual(NULL), mCheckSnapToGrid(NULL), @@ -698,6 +699,7 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) tool == LLToolCompScale::getInstance() || tool == LLToolFace::getInstance() || tool == LLToolIndividual::getInstance() || + tool == QToolAlign::getInstance() || tool == LLToolPipette::getInstance(); mBtnEdit ->setToggleState( edit_visible ); @@ -705,6 +707,7 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) mRadioPosition ->setVisible( edit_visible ); mRadioRotate ->setVisible( edit_visible ); mRadioStretch ->setVisible( edit_visible ); + mRadioAlign ->setVisible( edit_visible ); if (mRadioSelectFace) { mRadioSelectFace->setVisible( edit_visible ); @@ -720,6 +723,7 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) mRadioPosition ->set( tool == LLToolCompTranslate::getInstance() ); mRadioRotate ->set( tool == LLToolCompRotate::getInstance() ); mRadioStretch ->set( tool == LLToolCompScale::getInstance() ); + mRadioAlign->set( tool == QToolAlign::getInstance() ); if (mComboGridMode) { @@ -927,7 +931,7 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) childSetVisible("Strength:", land_visible); } - if (gSavedSettings.getBOOL("EditLinkedParts")) + if (gSavedSettings.getBOOL("EditLinkedParts") && LLSelectMgr::getInstance()->getEditSelection()->getObjectCount() == 1) { childSetVisible("link_num", !land_visible); } @@ -1254,8 +1258,18 @@ void LLFloaterTools::onClickLink(void* data) return; } - S32 max_linked_prims = gHippoLimits->getMaxLinkedPrims(); - if (max_linked_prims > -1) + S32 max_linked_prims = 0; + if(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()->usePhysics()) + { + //Physical - use phys prim limit + max_linked_prims = gHippoLimits->getMaxPhysLinkedPrims(); + } + else + { + //Non phys limit + max_linked_prims = gHippoLimits->getMaxLinkedPrims(); + } + if (max_linked_prims > -1) //-1 : no limits { S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); if (object_count > max_linked_prims + 1) @@ -1267,7 +1281,7 @@ void LLFloaterTools::onClickLink(void* data) return; } } - + if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() < 2) { LLNotifications::instance().add("CannotLinkIncompleteSet"); diff --git a/linden/indra/newview/llfloatertools.h b/linden/indra/newview/llfloatertools.h index ad5be6c86..bbf07ec50 100644 --- a/linden/indra/newview/llfloatertools.h +++ b/linden/indra/newview/llfloatertools.h @@ -140,6 +140,7 @@ class LLFloaterTools LLCheckBoxCtrl *mRadioRotate; LLCheckBoxCtrl *mRadioStretch; LLCheckBoxCtrl *mRadioSelectFace; + LLCheckBoxCtrl *mRadioAlign; LLCheckBoxCtrl *mCheckSelectIndividual; diff --git a/linden/indra/newview/llfloatertos.cpp b/linden/indra/newview/llfloatertos.cpp index 52d7b1f3c..ac4a06b17 100644 --- a/linden/indra/newview/llfloatertos.cpp +++ b/linden/indra/newview/llfloatertos.cpp @@ -1,284 +1,305 @@ -/** - * @file llfloatertos.cpp - * @brief Terms of Service Agreement dialog - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloatertos.h" - -// viewer includes -#include "llagent.h" -#include "llappviewer.h" -#include "llstartup.h" -#include "llviewerstats.h" -#include "llviewertexteditor.h" -#include "llviewerwindow.h" - -// linden library includes -#include "llbutton.h" -#include "llhttpclient.h" -#include "llhttpstatuscodes.h" // for HTTP_FOUND -#include "llradiogroup.h" -#include "lltextbox.h" -#include "llui.h" -#include "lluictrlfactory.h" -#include "llvfile.h" -#include "message.h" - - -// static -LLFloaterTOS* LLFloaterTOS::sInstance = NULL; - -// static -LLFloaterTOS* LLFloaterTOS::show(ETOSType type, const std::string & message) -{ - if( !LLFloaterTOS::sInstance ) - { - LLFloaterTOS::sInstance = new LLFloaterTOS(type, message); - } - - if (type == TOS_TOS) - { - LLUICtrlFactory::getInstance()->buildFloater(LLFloaterTOS::sInstance, "floater_tos.xml"); - } - else - { - LLUICtrlFactory::getInstance()->buildFloater(LLFloaterTOS::sInstance, "floater_critical.xml"); - } - - return LLFloaterTOS::sInstance; -} - - -LLFloaterTOS::LLFloaterTOS(ETOSType type, const std::string & message) -: LLModalDialog( std::string(" "), 100, 100 ), - mType(type), - mMessage(message), - mWebBrowserWindowId( 0 ), - mLoadCompleteCount( 0 ) -{ -} - -// helper class that trys to download a URL from a web site and calls a method -// on parent class indicating if the web server is working or not -class LLIamHereTOS : public LLHTTPClient::Responder -{ - private: - LLIamHereTOS( LLFloaterTOS* parent ) : - mParent( parent ) - {} - - LLFloaterTOS* mParent; - - public: - - static boost::intrusive_ptr< LLIamHereTOS > build( LLFloaterTOS* parent ) - { - return boost::intrusive_ptr< LLIamHereTOS >( new LLIamHereTOS( parent ) ); - }; - - virtual void setParent( LLFloaterTOS* parentIn ) - { - mParent = parentIn; - }; - - virtual void result( const LLSD& content ) - { - if ( mParent ) - mParent->setSiteIsAlive( true ); - }; - - virtual void error( U32 status, const std::string& reason ) - { - if ( mParent ) - { - // *HACK: For purposes of this alive check, 302 Found - // (aka Moved Temporarily) is considered alive. The web site - // redirects this link to a "cache busting" temporary URL. JC - bool alive = (status == HTTP_FOUND); - mParent->setSiteIsAlive( alive ); - } - }; -}; - -// this is global and not a class member to keep crud out of the header file -namespace { - boost::intrusive_ptr< LLIamHereTOS > gResponsePtr = 0; -}; - -BOOL LLFloaterTOS::postBuild() -{ - childSetAction("Continue", onContinue, this); - childSetAction("Cancel", onCancel, this); - childSetCommitCallback("agree_chk", updateAgree, this); - - if ( mType != TOS_TOS ) - { - llinfos << "tos_type != TOS_TOS" << llendl; - // this displays the critical message - LLTextEditor *editor = getChild<LLTextEditor>("tos_text"); - editor->setHandleEditKeysDirectly( TRUE ); - editor->setEnabled( FALSE ); - editor->setWordWrap(TRUE); - editor->setFocus(TRUE); - // editor->setValue(LLSD(mMessage)); - editor->setValue(mMessage); - - return TRUE; - } - - // disable Agree to TOS radio button until the page has fully loaded - LLCheckBoxCtrl* tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk"); - tos_agreement->setEnabled( false ); - - // hide the SL text widget if we're displaying TOS with using a browser widget. - LLTextEditor *editor = getChild<LLTextEditor>("tos_text"); - editor->setVisible(FALSE); - - LLWebBrowserCtrl* web_browser = getChild<LLWebBrowserCtrl>("tos_html"); - if ( web_browser ) - { - // start to observe it so we see navigate complete events - web_browser->addObserver( this ); - - gResponsePtr = LLIamHereTOS::build( this ); - LLHTTPClient::head( getString( "real_url" ), gResponsePtr ); - } - - return TRUE; -} - -void LLFloaterTOS::setSiteIsAlive( bool alive ) -{ - // only do this for TOS pages - if ( mType == TOS_TOS ) - { - LLWebBrowserCtrl* web_browser = getChild<LLWebBrowserCtrl>("tos_html"); - // if the contents of the site was retrieved - if ( alive ) - { - if ( web_browser ) - { - // navigate to the "real" page - web_browser->navigateTo( getString( "real_url" ) ); - }; - } - else - { - // normally this is set when navigation to TOS page navigation completes (so you can't accept before TOS loads) - // but if the page is unavailable, we need to do this now - LLCheckBoxCtrl* tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk"); - tos_agreement->setEnabled( true ); - }; - }; -} - -LLFloaterTOS::~LLFloaterTOS() -{ - // stop obsaerving events - LLWebBrowserCtrl* web_browser = getChild<LLWebBrowserCtrl>("tos_html"); - if ( web_browser ) - { - web_browser->remObserver( this ); - }; - - // tell the responder we're not here anymore - if ( gResponsePtr ) - gResponsePtr->setParent( 0 ); - - LLFloaterTOS::sInstance = NULL; -} - -// virtual -void LLFloaterTOS::draw() -{ - // draw children - LLModalDialog::draw(); -} - -// static -void LLFloaterTOS::updateAgree(LLUICtrl*, void* userdata ) -{ - LLFloaterTOS* self = (LLFloaterTOS*) userdata; - bool agree = self->childGetValue("agree_chk").asBoolean(); - self->childSetEnabled("Continue", agree); -} - -// static -void LLFloaterTOS::onContinue( void* userdata ) -{ - LLFloaterTOS* self = (LLFloaterTOS*) userdata; - llinfos << "User agrees with TOS." << llendl; - if (self->mType == TOS_TOS) - { - gAcceptTOS = TRUE; - } - else - { - gAcceptCriticalMessage = TRUE; - } - - // Testing TOS dialog - #if ! LL_RELEASE_FOR_DOWNLOAD - if ( LLStartUp::getStartupState() == STATE_LOGIN_WAIT ) - { - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - } - else - #endif - - LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); // Go back and finish authentication - self->close(); // destroys this object -} - -// static -void LLFloaterTOS::onCancel( void* userdata ) -{ - LLFloaterTOS* self = (LLFloaterTOS*) userdata; - llinfos << "User disagrees with TOS." << llendl; - LLNotifications::instance().add("MustAgreeToLogIn", LLSD(), LLSD(), login_alert_done); - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - self->mLoadCompleteCount = 0; // reset counter for next time we come to TOS - self->close(); // destroys this object -} - -//virtual -void LLFloaterTOS::onNavigateComplete( const EventType& eventIn ) -{ - // skip past the loading screen navigate complete - if ( ++mLoadCompleteCount == 2 ) - { - llinfos << "NAVIGATE COMPLETE" << llendl; - // enable Agree to TOS radio button now that page has loaded - LLCheckBoxCtrl * tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk"); - tos_agreement->setEnabled( true ); - }; -} +/** + * @file llfloatertos.cpp + * @brief Terms of Service Agreement dialog + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloatertos.h" + +// viewer includes +#include "llagent.h" +#include "llappviewer.h" +#include "llstartup.h" +#include "llviewerstats.h" +#include "llviewertexteditor.h" +#include "llviewerwindow.h" + +// linden library includes +#include "llbutton.h" +#include "llhttpclient.h" +#include "llhttpstatuscodes.h" // for HTTP_FOUND +#include "llradiogroup.h" +#include "lltextbox.h" +#include "llui.h" +#include "lluictrlfactory.h" +#include "llvfile.h" +#include "message.h" +#include "hippogridmanager.h" + + +// static +LLFloaterTOS* LLFloaterTOS::sInstance = NULL; + +// static +LLFloaterTOS* LLFloaterTOS::show(ETOSType type, const std::string & message) +{ + if( !LLFloaterTOS::sInstance ) + { + LLFloaterTOS::sInstance = new LLFloaterTOS(type, message); + } + + if (type == TOS_TOS) + { + LLUICtrlFactory::getInstance()->buildFloater(LLFloaterTOS::sInstance, "floater_tos.xml"); + } + else + { + LLUICtrlFactory::getInstance()->buildFloater(LLFloaterTOS::sInstance, "floater_critical.xml"); + } + + return LLFloaterTOS::sInstance; +} + + +LLFloaterTOS::LLFloaterTOS(ETOSType type, const std::string & message) +: LLModalDialog( std::string(" "), 100, 100 ), + mType(type), + mMessage(message), + mWebBrowserWindowId( 0 ), + mLoadCompleteCount( 0 ) +{ +} + +// helper class that trys to download a URL from a web site and calls a method +// on parent class indicating if the web server is working or not +class LLIamHereTOS : public LLHTTPClient::Responder +{ + private: + LLIamHereTOS( LLFloaterTOS* parent ) : + mParent( parent ) + {} + + LLFloaterTOS* mParent; + + public: + + static boost::intrusive_ptr< LLIamHereTOS > build( LLFloaterTOS* parent ) + { + return boost::intrusive_ptr< LLIamHereTOS >( new LLIamHereTOS( parent ) ); + }; + + virtual void setParent( LLFloaterTOS* parentIn ) + { + mParent = parentIn; + }; + + virtual void result( const LLSD& content ) + { + if ( mParent ) + mParent->setSiteIsAlive( true ); + }; + + virtual void error( U32 status, const std::string& reason ) + { + if ( mParent ) + { + // *HACK: For purposes of this alive check, 302 Found + // (aka Moved Temporarily) is considered alive. The web site + // redirects this link to a "cache busting" temporary URL. JC + bool alive = (status == HTTP_FOUND); + mParent->setSiteIsAlive( alive ); + } + }; +}; + +// this is global and not a class member to keep crud out of the header file +namespace { + boost::intrusive_ptr< LLIamHereTOS > gResponsePtr = 0; +}; + +BOOL LLFloaterTOS::postBuild() +{ + childSetAction("Continue", onContinue, this); + childSetAction("Cancel", onCancel, this); + childSetCommitCallback("agree_chk", updateAgree, this); + + LLCheckBoxCtrl* tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk"); + tos_agreement->setEnabled( true ); + + //Always set this so that the TOS is displayed whether the web browser pops up or not. + LLTextEditor *editor = getChild<LLTextEditor>("tos_text"); + editor->setHandleEditKeysDirectly( TRUE ); + editor->setEnabled( FALSE ); + editor->setWordWrap(TRUE); + editor->setFocus(TRUE); + editor->setValue(LLSD(mMessage)); + LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("tos_html"); + if (web_browser) + { + //Disable for critical messages and text messages, it is reenabled later + web_browser->setVisible( FALSE ); + } + + if ( mType != TOS_TOS ) + { + // this displays the critical message only + return TRUE; + } + bool use_web_browser = false; + + //Check to see if the message is a link to display + std::string token = "http://"; + std::string::size_type iIndex = mMessage.rfind(token); + //IF it has http:// in it, we use the web browser + if(iIndex != std::string::npos && mMessage.length() >= 2) + { + // it exists + use_web_browser = true; + } + else if (gHippoGridManager->getConnectedGrid()->isSecondLife()) + { + //Its SL, use the browser for it as thats what it should do + use_web_browser = true; + } + + if ( web_browser && use_web_browser) + { + // hide the SL text widget if we're displaying TOS with using a browser widget. + LLTextEditor *editor = getChild<LLTextEditor>("tos_text"); + editor->setVisible( FALSE ); + + // disable Agree to TOS radio button until the page has fully loaded + tos_agreement->setEnabled( false ); + + // Reenable the web browser + web_browser->setVisible( TRUE ); + + web_browser->addObserver(this); + gResponsePtr = LLIamHereTOS::build( this ); + LLHTTPClient::head( getString( "real_url" ), gResponsePtr ); + } + + return TRUE; +} + +void LLFloaterTOS::setSiteIsAlive( bool alive ) +{ + // only do this for TOS pages + if ( mType == TOS_TOS ) + { + LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("tos_html"); + // if the contents of the site was retrieved + if ( alive ) + { + if ( web_browser ) + { + // navigate to the "real" page + web_browser->navigateTo( getString( "real_url" ) ); + }; + } + else + { + // normally this is set when navigation to TOS page navigation completes (so you can't accept before TOS loads) + // but if the page is unavailable, we need to do this now + LLCheckBoxCtrl* tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk"); + tos_agreement->setEnabled( true ); + }; + }; +} + +LLFloaterTOS::~LLFloaterTOS() +{ + + // tell the responder we're not here anymore + if ( gResponsePtr ) + gResponsePtr->setParent( 0 ); + + LLFloaterTOS::sInstance = NULL; +} + +// virtual +void LLFloaterTOS::draw() +{ + // draw children + LLModalDialog::draw(); +} + +// static +void LLFloaterTOS::updateAgree(LLUICtrl*, void* userdata ) +{ + LLFloaterTOS* self = (LLFloaterTOS*) userdata; + bool agree = self->childGetValue("agree_chk").asBoolean(); + self->childSetEnabled("Continue", agree); +} + +// static +void LLFloaterTOS::onContinue( void* userdata ) +{ + LLFloaterTOS* self = (LLFloaterTOS*) userdata; + llinfos << "User agrees with TOS." << llendl; + if (self->mType == TOS_TOS) + { + gAcceptTOS = TRUE; + } + else + { + gAcceptCriticalMessage = TRUE; + } + + // Testing TOS dialog + #if ! LL_RELEASE_FOR_DOWNLOAD + if ( LLStartUp::getStartupState() == STATE_LOGIN_WAIT ) + { + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + } + else + #endif + + LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); // Go back and finish authentication + self->close(); // destroys this object +} + +// static +void LLFloaterTOS::onCancel( void* userdata ) +{ + LLFloaterTOS* self = (LLFloaterTOS*) userdata; + llinfos << "User disagrees with TOS." << llendl; + LLNotifications::instance().add("MustAgreeToLogIn", LLSD(), LLSD(), login_alert_done); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + self->mLoadCompleteCount = 0; // reset counter for next time we come to TOS + self->close(); // destroys this object +} + +//virtual +void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event) +{ + if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) + { + // skip past the loading screen navigate complete + if ( ++mLoadCompleteCount == 2 ) + { + llinfos << "NAVIGATE COMPLETE" << llendl; + // enable Agree to TOS radio button now that page has loaded + LLCheckBoxCtrl * tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk"); + tos_agreement->setEnabled( true ); + } + } +} diff --git a/linden/indra/newview/llfloatertos.h b/linden/indra/newview/llfloatertos.h index dbec3ff8b..c5d587897 100644 --- a/linden/indra/newview/llfloatertos.h +++ b/linden/indra/newview/llfloatertos.h @@ -35,7 +35,7 @@ #include "llmodaldialog.h" #include "llassetstorage.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" class LLButton; class LLRadioGroup; @@ -45,7 +45,7 @@ class LLUUID; class LLFloaterTOS : public LLModalDialog, - public LLWebBrowserCtrlObserver + public LLViewerMediaObserver { public: virtual ~LLFloaterTOS(); @@ -70,7 +70,8 @@ class LLFloaterTOS : void setSiteIsAlive( bool alive ); - virtual void onNavigateComplete( const EventType& eventIn ); + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); private: // Asset_id is overwritten with LLUUID::null when agree is clicked. diff --git a/linden/indra/newview/llfloaterurlentry.cpp b/linden/indra/newview/llfloaterurlentry.cpp index 9d91aa986..8d483e59e 100644 --- a/linden/indra/newview/llfloaterurlentry.cpp +++ b/linden/indra/newview/llfloaterurlentry.cpp @@ -227,7 +227,7 @@ void LLFloaterURLEntry::onBtnOK( void* userdata ) } // Discover the MIME type only for "http" scheme. - if(scheme == "http") + if(scheme == "http" || scheme == "https") { LLHTTPClient::getHeaderOnly( media_url, new LLMediaTypeResponder(self->getHandle())); diff --git a/linden/indra/newview/llfloaterwater.cpp b/linden/indra/newview/llfloaterwater.cpp index c4b6d0d98..782c56e72 100644 --- a/linden/indra/newview/llfloaterwater.cpp +++ b/linden/indra/newview/llfloaterwater.cpp @@ -64,6 +64,8 @@ #include "llwaterparammanager.h" #include "llpostprocess.h" +#include "wlfloaterwindlightsend.h" + #undef max LLFloaterWater* LLFloaterWater::sWaterMenu = NULL; @@ -680,6 +682,12 @@ void LLFloaterWater::onSavePreset(LLUICtrl* ctrl, void* userData) } } + else if (ctrl->getValue().asString() == "send_to_server_item") + { + //Open the other box + WLFloaterWindLightSend::instance(); + WLFloaterWindLightSend::instance()->open(); + } else { LLWaterParamManager::instance()->mCurParams.mName = diff --git a/linden/indra/newview/llfloaterwindlight.cpp b/linden/indra/newview/llfloaterwindlight.cpp index be3c1fd0a..493723276 100644 --- a/linden/indra/newview/llfloaterwindlight.cpp +++ b/linden/indra/newview/llfloaterwindlight.cpp @@ -63,6 +63,9 @@ #include "llwlparamset.h" #include "llwlparammanager.h" #include "llpostprocess.h" +#include "wlfloaterwindlightsend.h" +#include "llworld.h" +#include "hippolimits.h" #undef max @@ -216,7 +219,9 @@ void LLFloaterWindLight::initCallbacks(void) { childSetCommitCallback("WLCloudScrollX", onCloudScrollXMoved, NULL); childSetCommitCallback("WLCloudScrollY", onCloudScrollYMoved, NULL); childSetCommitCallback("WLDistanceMult", onFloatControlMoved, ¶m_mgr->mDistanceMult); - childSetCommitCallback("DrawClassicClouds", LLSavedSettingsGlue::setBOOL, (void*)"SkyUseClassicClouds"); + childSetCommitCallback("DrawClassicClouds", onCloudDrawToggled, NULL); + childSetCommitCallback("WLCloudHeight", onCloudHeightMoved, NULL); + childSetCommitCallback("WLCloudRange", onCloudRangeMoved, NULL); // WL Top childSetAction("WLDayCycleMenuButton", onOpenDayCycle, NULL); @@ -425,7 +430,21 @@ void LLFloaterWindLight::syncMenu() bool lockY = !param_mgr->mCurParams.getEnableCloudScrollY(); childSetValue("WLCloudLockX", lockX); childSetValue("WLCloudLockY", lockY); - childSetValue("DrawClassicClouds", gSavedSettings.getBOOL("SkyUseClassicClouds")); + childSetValue("DrawClassicClouds", gHippoLimits->skyUseClassicClouds); + + childSetValue("WLCloudHeight", gSavedSettings.getF32("ClassicCloudHeight")); + childSetValue("WLCloudRange", gSavedSettings.getF32("ClassicCloudRange")); + + if(!gHippoLimits->skyUseClassicClouds) + { + childDisable("WLCloudHeight"); + childDisable("WLCloudRange"); + } + else + { + childEnable("WLCloudHeight"); + childEnable("WLCloudRange"); + } // disable if locked, enable if not if(lockX) @@ -874,6 +893,12 @@ void LLFloaterWindLight::onSavePreset(LLUICtrl* ctrl, void* userData) } } + else if (ctrl->getValue().asString() == "send_to_server_item") + { + //Open the other box + WLFloaterWindLightSend::instance(); + WLFloaterWindLightSend::instance()->open(); + } else { // check to see if it's a default and shouldn't be overwritten @@ -1046,6 +1071,35 @@ void LLFloaterWindLight::onCloudScrollYMoved(LLUICtrl* ctrl, void* userData) // *HACK all cloud scrolling is off by an additive of 10. LLWLParamManager::instance()->mCurParams.setCloudScrollY(sldrCtrl->getValueF32() + 10.0f); } +void LLFloaterWindLight::onCloudDrawToggled(LLUICtrl* ctrl, void* userData) +{ + LLCheckBoxCtrl* cbCtrl = static_cast<LLCheckBoxCtrl*>(ctrl); + + bool lock = cbCtrl->get(); + gHippoLimits->skyUseClassicClouds = lock; + + LLWorld::getInstance()->rebuildClouds(gAgent.getRegion()); +} + +void LLFloaterWindLight::onCloudHeightMoved(LLUICtrl* ctrl, void* userData) +{ + deactivateAnimator(); + + LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl); + + gSavedSettings.setF32("ClassicCloudHeight", sldrCtrl->getValueF32()); + + LLWorld::getInstance()->rebuildClouds(gAgent.getRegion()); +} + +void LLFloaterWindLight::onCloudRangeMoved(LLUICtrl* ctrl, void* userData) +{ + deactivateAnimator(); + + LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl); + + gSavedSettings.setF32("ClassicCloudRange", sldrCtrl->getValueF32()); +} void LLFloaterWindLight::onCloudScrollXToggled(LLUICtrl* ctrl, void* userData) { diff --git a/linden/indra/newview/llfloaterwindlight.h b/linden/indra/newview/llfloaterwindlight.h index b9e53114a..24b0e8798 100644 --- a/linden/indra/newview/llfloaterwindlight.h +++ b/linden/indra/newview/llfloaterwindlight.h @@ -118,6 +118,10 @@ class LLFloaterWindLight : public LLFloater static void onCloudScrollXToggled(LLUICtrl* ctrl, void* userData); static void onCloudScrollYToggled(LLUICtrl* ctrl, void* userData); + static void onCloudDrawToggled(LLUICtrl* ctrl, void* userData); + static void onCloudHeightMoved(LLUICtrl* ctrl, void* userData); + static void onCloudRangeMoved(LLUICtrl* ctrl, void* userData); + //// menu management /// show off our menu diff --git a/linden/indra/newview/llfloaterworldmap.cpp b/linden/indra/newview/llfloaterworldmap.cpp index 0a01ca70a..47f336196 100644 --- a/linden/indra/newview/llfloaterworldmap.cpp +++ b/linden/indra/newview/llfloaterworldmap.cpp @@ -70,7 +70,7 @@ #include "llglheaders.h" -#include "hippoLimits.h" +#include "hippolimits.h" // [RLVa:KB] #include "rlvhandler.h" diff --git a/linden/indra/newview/llfolderview.h b/linden/indra/newview/llfolderview.h index 9fad72e7c..40da66942 100644 --- a/linden/indra/newview/llfolderview.h +++ b/linden/indra/newview/llfolderview.h @@ -97,7 +97,7 @@ class LLFolderViewEventListener virtual void move( LLFolderViewEventListener* parent_listener ) = 0; virtual BOOL isItemCopyable() const = 0; virtual BOOL copyToClipboard() const = 0; - virtual void cutToClipboard() = 0; + virtual BOOL cutToClipboard() const = 0; virtual BOOL isClipboardPasteable() const = 0; virtual void pasteFromClipboard() = 0; virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0; diff --git a/linden/indra/newview/llgesturemgr.cpp b/linden/indra/newview/llgesturemgr.cpp index bb678d7a0..d1c3ee376 100644 --- a/linden/indra/newview/llgesturemgr.cpp +++ b/linden/indra/newview/llgesturemgr.cpp @@ -565,6 +565,8 @@ BOOL LLGestureManager::triggerAndReviseString(const std::string &utf8str, std::s found_gestures = TRUE; } } + +#if 0 // MoonWorld: Kill all the /icanhas insanity (opens loads of webbrowser pages). else if (LLStringUtil::compareInsensitive("/icanhaseasteregg", cur_token) == 0 || LLStringUtil::compareInsensitive("/icanhaseastereggs", cur_token) == 0) { @@ -803,6 +805,7 @@ BOOL LLGestureManager::triggerAndReviseString(const std::string &utf8str, std::s } return TRUE; } +#endif // NO ICANHAS } diff --git a/linden/indra/newview/llgivemoney.cpp b/linden/indra/newview/llgivemoney.cpp index 6c6933424..ee2bf6342 100644 --- a/linden/indra/newview/llgivemoney.cpp +++ b/linden/indra/newview/llgivemoney.cpp @@ -52,7 +52,7 @@ #include "lltransactiontypes.h" #include "lluictrlfactory.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs diff --git a/linden/indra/newview/llglsandbox.cpp b/linden/indra/newview/llglsandbox.cpp index a4871508b..98c4d06df 100644 --- a/linden/indra/newview/llglsandbox.cpp +++ b/linden/indra/newview/llglsandbox.cpp @@ -275,7 +275,11 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) virtual bool apply(LLViewerObject* vobjp) { LLDrawable* drawable = vobjp->mDrawable; - if (!drawable || vobjp->getPCode() != LL_PCODE_VOLUME || vobjp->isAttachment()) + if (!drawable || + ((vobjp->getPCode() != LL_PCODE_VOLUME) && + (vobjp->getPCode() != LL_PCODE_LEGACY_TREE) && + (vobjp->getPCode() != LL_PCODE_LEGACY_GRASS) )|| + vobjp->isAttachment()) { return true; } @@ -326,7 +330,9 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) LLViewerObject* vobjp = drawable->getVObj(); if (!drawable || !vobjp || - vobjp->getPCode() != LL_PCODE_VOLUME || + ((vobjp->getPCode() != LL_PCODE_VOLUME) && + (vobjp->getPCode() != LL_PCODE_LEGACY_TREE) && + (vobjp->getPCode() != LL_PCODE_LEGACY_GRASS) )|| vobjp->isAttachment() || (deselect && !vobjp->isSelected())) { diff --git a/linden/indra/newview/llhomelocationresponder.cpp b/linden/indra/newview/llhomelocationresponder.cpp index 3ef58e756..c00d8e719 100644 --- a/linden/indra/newview/llhomelocationresponder.cpp +++ b/linden/indra/newview/llhomelocationresponder.cpp @@ -100,10 +100,13 @@ void LLHomeLocationResponder::result( const LLSD& content ) LLViewerRegion *viewer_region = gAgent.getRegion(); gAgent.setHomePosRegion( viewer_region->getHandle(), agent_pos ); + gAgent.takeHomeScreenshot(); + } } -void LLHomeLocationResponder::error( const LLSD& content ) +void LLHomeLocationResponder::error( U32 status, const std::string& reason ) { - llinfos << "received error(" << ll_pretty_print_sd( content ) << ")" << llendl; + llinfos << "received error(" << reason << ")" << llendl; } + diff --git a/linden/indra/newview/llhomelocationresponder.h b/linden/indra/newview/llhomelocationresponder.h index 1e222cd5b..3a1d8ebfe 100644 --- a/linden/indra/newview/llhomelocationresponder.h +++ b/linden/indra/newview/llhomelocationresponder.h @@ -42,7 +42,7 @@ class LLHomeLocationResponder : public LLHTTPClient::Responder { virtual void result( const LLSD& content ); - virtual void error( const LLSD& content ); + virtual void error( U32 status, const std::string& reason ); }; #endif diff --git a/linden/indra/newview/llhoverview.cpp b/linden/indra/newview/llhoverview.cpp index 120bbaafe..10d27cdd2 100644 --- a/linden/indra/newview/llhoverview.cpp +++ b/linden/indra/newview/llhoverview.cpp @@ -73,7 +73,7 @@ #include "llhudmanager.h" // For testing effects #include "llhudeffect.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // [RLVa:KB] #include "rlvhandler.h" @@ -158,12 +158,13 @@ void LLHoverView::updateHover(LLTool* current_tool) void LLHoverView::pickCallback(const LLPickInfo& pick_info) { + gHoverView->mLastPickInfo = pick_info; LLViewerObject* hit_obj = pick_info.getObject(); if (hit_obj) { gHoverView->setHoverActive(TRUE); - LLSelectMgr::getInstance()->setHoverObject(hit_obj); + LLSelectMgr::getInstance()->setHoverObject(hit_obj, pick_info.mObjectFace); gHoverView->mLastHoverObject = hit_obj; gHoverView->mHoverOffset = pick_info.mObjectOffset; } diff --git a/linden/indra/newview/llhoverview.h b/linden/indra/newview/llhoverview.h index 0891118b7..d0bb28d83 100644 --- a/linden/indra/newview/llhoverview.h +++ b/linden/indra/newview/llhoverview.h @@ -42,6 +42,7 @@ #include "v3dmath.h" #include "lldarray.h" +#include "llviewerwindow.h" #include "llviewerobject.h" class LLTool; @@ -79,6 +80,7 @@ class LLHoverView : public LLView BOOL isHoveringLand() const; LLViewerObject* getLastHoverObject() const; + LLPickInfo getPickInfo() { return mLastPickInfo; } static void pickCallback(const LLPickInfo& info); @@ -103,6 +105,7 @@ class LLHoverView : public LLView // If not null and not dead, we're over an object. LLPointer<LLViewerObject> mLastHoverObject; + LLPickInfo mLastPickInfo; // If not LLVector3d::ZERO, we're over land. LLVector3d mHoverLandGlobal; diff --git a/linden/indra/newview/llhudeffectlookat.cpp b/linden/indra/newview/llhudeffectlookat.cpp index 75e2f30da..ccd723f18 100644 --- a/linden/indra/newview/llhudeffectlookat.cpp +++ b/linden/indra/newview/llhudeffectlookat.cpp @@ -53,6 +53,7 @@ // [/RLVa:KB] #include "llxmltree.h" +#include "hippolimits.h" BOOL LLHUDEffectLookAt::sDebugLookAt = FALSE; @@ -553,7 +554,7 @@ void LLHUDEffectLookAt::setSourceObject(LLViewerObject* objectp) //----------------------------------------------------------------------------- void LLHUDEffectLookAt::render() { - if (sDebugLookAt && mSourceObject.notNull()) + if (sDebugLookAt && mSourceObject.notNull() && gHippoLimits->mAllowMinimap) //Has to have allow minimap as well, otherwise it defeats the purpose of no minimap { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); diff --git a/linden/indra/newview/llhudview.cpp b/linden/indra/newview/llhudview.cpp index 198514ce0..afcdd73c9 100644 --- a/linden/indra/newview/llhudview.cpp +++ b/linden/indra/newview/llhudview.cpp @@ -48,14 +48,19 @@ #include "lltracker.h" #include "llviewercamera.h" #include "llui.h" +#include "lluictrlfactory.h" LLHUDView *gHUDView = NULL; const S32 HUD_ARROW_SIZE = 32; -LLHUDView::LLHUDView() -: LLPanel() -{ } + + +LLHUDView::LLHUDView(const LLRect& r) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_hud.xml"); + userSetShape(r); +} LLHUDView::~LLHUDView() { } @@ -64,6 +69,7 @@ LLHUDView::~LLHUDView() void LLHUDView::draw() { LLTracker::drawHUDArrow(); + LLView::draw(); } @@ -89,4 +95,3 @@ BOOL LLHUDView::handleMouseDown(S32 x, S32 y, MASK mask) } return LLView::handleMouseDown(x, y, mask); } - diff --git a/linden/indra/newview/llhudview.h b/linden/indra/newview/llhudview.h index 7859e7f8b..05ff9c859 100644 --- a/linden/indra/newview/llhudview.h +++ b/linden/indra/newview/llhudview.h @@ -42,7 +42,7 @@ class LLHUDView : public LLPanel { public: - LLHUDView(); + LLHUDView(const LLRect& rect); virtual ~LLHUDView(); virtual void draw(); diff --git a/linden/indra/newview/llimpanel.cpp b/linden/indra/newview/llimpanel.cpp index d9e822f1d..41727f2b0 100644 --- a/linden/indra/newview/llimpanel.cpp +++ b/linden/indra/newview/llimpanel.cpp @@ -2202,8 +2202,8 @@ void LLFloaterIMPanel::sendMsg() LLViewerStats::getInstance()->incStat(LLViewerStats::ST_IM_COUNT); + mInputEditor->setText(LLStringUtil::null); } - mInputEditor->setText(LLStringUtil::null); // Don't need to actually send the typing stop message, the other // client will infer it from receiving the message. diff --git a/linden/indra/newview/llimview.cpp b/linden/indra/newview/llimview.cpp index 225340471..02f6a82b2 100644 --- a/linden/indra/newview/llimview.cpp +++ b/linden/indra/newview/llimview.cpp @@ -1363,7 +1363,7 @@ void LLIMMgr::saveIgnoreGroup() { // llinfos << "saving ignore_groups.xml" << llendl; - std::string user_dir = gDirUtilp->getLindenUserDir(); + std::string user_dir = gDirUtilp->getLindenUserDir(true); if (!user_dir.empty()) { std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "ignore_groups.xml"); diff --git a/linden/indra/newview/llinventoryactions.cpp b/linden/indra/newview/llinventoryactions.cpp index 7ae96ad57..25a4a4bfc 100644 --- a/linden/indra/newview/llinventoryactions.cpp +++ b/linden/indra/newview/llinventoryactions.cpp @@ -119,6 +119,11 @@ bool doToSelected(LLFolderView* folder, std::string action) LLInventoryClipboard::instance().reset(); } + if ("cut" == action) + { + LLInventoryClipboard::instance().reset(); + } + std::set<LLUUID> selected_items; folder->getSelectionList(selected_items); diff --git a/linden/indra/newview/llinventorybridge.cpp b/linden/indra/newview/llinventorybridge.cpp index b1627b523..f71df2d2d 100644 --- a/linden/indra/newview/llinventorybridge.cpp +++ b/linden/indra/newview/llinventorybridge.cpp @@ -463,6 +463,12 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, std::vector<std::str items.push_back(std::string("Copy Separator")); + items.push_back(std::string("Cut")); + if (!isItemCopyable()) + { + disabled_items.push_back(std::string("Cut")); + } + items.push_back(std::string("Copy")); if (!isItemCopyable()) { @@ -813,6 +819,11 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, copyToClipboard(); return; } + else if ("cut" == action) + { + cutToClipboard(); + return; + } else if ("paste" == action) { // Single item only @@ -1086,6 +1097,15 @@ BOOL LLItemBridge::copyToClipboard() const } return FALSE; } +BOOL LLItemBridge::cutToClipboard() const +{ + if(isItemCopyable()) + { + LLInventoryClipboard::instance().addCut(mUUID); + return TRUE; + } + return FALSE; +} LLViewerInventoryItem* LLItemBridge::getItem() const { @@ -1890,6 +1910,35 @@ void LLFolderBridge::pasteFromClipboard() LLPointer<LLInventoryCallback>(NULL)); } } + //Do cuts as well + LLInventoryClipboard::instance().retrieveCuts(objects); + count = objects.count(); + parent_id = mUUID; + for(S32 i = 0; i < count; i++) + { + item = model->getItem(objects.get(i)); + if (item) + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + parent_id, + std::string(), + LLPointer<LLInventoryCallback>(NULL)); + LLInventoryCategory* cat = model->getCategory(item->getUUID()); + if(cat) + { + model->purgeDescendentsOf(mUUID); + } + LLInventoryObject* obj = model->getObject(item->getUUID()); + if(!obj) return; + obj->removeFromServer(); + LLPreview::hide(item->getUUID()); + model->deleteObject(item->getUUID()); + model->notifyObservers(); + } + } } } diff --git a/linden/indra/newview/llinventorybridge.h b/linden/indra/newview/llinventorybridge.h index 45486ed74..5a53aa5b4 100644 --- a/linden/indra/newview/llinventorybridge.h +++ b/linden/indra/newview/llinventorybridge.h @@ -221,7 +221,7 @@ class LLInvFVBridge : public LLFolderViewEventListener virtual void move(LLFolderViewEventListener* new_parent_bridge) {} virtual BOOL isItemCopyable() const { return FALSE; } virtual BOOL copyToClipboard() const { return FALSE; } - virtual void cutToClipboard() {} + virtual BOOL cutToClipboard() const { return FALSE; } virtual BOOL isClipboardPasteable() const; virtual void pasteFromClipboard() {} void getClipboardEntries(bool show_asset_id, std::vector<std::string> &items, @@ -297,6 +297,7 @@ class LLItemBridge : public LLInvFVBridge virtual BOOL removeItem(); virtual BOOL isItemCopyable() const; virtual BOOL copyToClipboard() const; + virtual BOOL cutToClipboard() const; virtual BOOL hasChildren() const { return FALSE; } virtual BOOL isUpToDate() const { return TRUE; } diff --git a/linden/indra/newview/llinventoryclipboard.cpp b/linden/indra/newview/llinventoryclipboard.cpp index 94ffcbd45..95c22aa6f 100644 --- a/linden/indra/newview/llinventoryclipboard.cpp +++ b/linden/indra/newview/llinventoryclipboard.cpp @@ -60,6 +60,11 @@ void LLInventoryClipboard::add(const LLUUID& object) mObjects.put(object); } +void LLInventoryClipboard::addCut(const LLUUID& object) +{ + mCutObjects.put(object); +} + // this stores a single inventory object void LLInventoryClipboard::store(const LLUUID& object) { @@ -87,15 +92,26 @@ void LLInventoryClipboard::retrieve(LLDynamicArray<LLUUID>& inv_objects) const } } +void LLInventoryClipboard::retrieveCuts(LLDynamicArray<LLUUID>& inv_objects) const +{ + inv_objects.reset(); + S32 count = mCutObjects.count(); + for(S32 i = 0; i < count; i++) + { + inv_objects.put(mCutObjects[i]); + } +} + void LLInventoryClipboard::reset() { mObjects.reset(); + mCutObjects.reset(); } // returns true if the clipboard has something pasteable in it. BOOL LLInventoryClipboard::hasContents() const { - return (mObjects.count() > 0); + return (mObjects.count() > 0) || (mCutObjects.count() > 0); } diff --git a/linden/indra/newview/llinventoryclipboard.h b/linden/indra/newview/llinventoryclipboard.h index 7a2cf15d6..99e84505a 100644 --- a/linden/indra/newview/llinventoryclipboard.h +++ b/linden/indra/newview/llinventoryclipboard.h @@ -54,6 +54,8 @@ class LLInventoryClipboard // this method adds to the current list. void add(const LLUUID& object); + void addCut(const LLUUID& object); + // this stores a single inventory object void store(const LLUUID& object); @@ -64,6 +66,10 @@ class LLInventoryClipboard // into the array provided. void retrieve(LLDynamicArray<LLUUID>& inventory_objects) const; + // this method gets the objects in the clipboard by copying them + // into the array provided. + void retrieveCuts(LLDynamicArray<LLUUID>& inventory_objects) const; + // this method empties out the clipboard void reset(); @@ -74,6 +80,7 @@ class LLInventoryClipboard static LLInventoryClipboard sInstance; LLDynamicArray<LLUUID> mObjects; + LLDynamicArray<LLUUID> mCutObjects; public: // please don't actually call these diff --git a/linden/indra/newview/llloginhandler.cpp b/linden/indra/newview/llloginhandler.cpp index 636639856..30b05ef98 100644 --- a/linden/indra/newview/llloginhandler.cpp +++ b/linden/indra/newview/llloginhandler.cpp @@ -111,7 +111,7 @@ void LLLoginHandler::parse(const LLSD& queryMap) bool LLLoginHandler::handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { parse(query_map); diff --git a/linden/indra/newview/llloginhandler.h b/linden/indra/newview/llloginhandler.h index c76d7e827..0844b80c7 100644 --- a/linden/indra/newview/llloginhandler.h +++ b/linden/indra/newview/llloginhandler.h @@ -40,7 +40,7 @@ class LLLoginHandler : public LLCommandHandler public: // allow from external browsers LLLoginHandler() : LLCommandHandler("login", false) { } - /*virtual*/ bool handle(const LLSD& tokens, const LLSD& query_map, LLWebBrowserCtrl* web); + /*virtual*/ bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web); // Fill in our internal fields from a SLURL like // secondlife:///app/login?first=Bob&last=Dobbs diff --git a/linden/indra/newview/llmanipscale.cpp b/linden/indra/newview/llmanipscale.cpp index fa7e85f95..b38abe441 100644 --- a/linden/indra/newview/llmanipscale.cpp +++ b/linden/indra/newview/llmanipscale.cpp @@ -63,7 +63,7 @@ #include "v2math.h" #include "llvoavatar.h" -#include "hippoLimits.h" +#include "hippolimits.h" const F32 MAX_MANIP_SELECT_DISTANCE_SQUARED = 11.f * 11.f; @@ -1523,7 +1523,7 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) F32 max_subdivisions = sGridMaxSubdivisionLevel; F32 grid_alpha = gSavedSettings.getF32("GridOpacity"); - F32 max_point_on_scale_line = partToMaxScale(mManipPart, bbox); + F32 max_point_on_scale_line = llmin(partToMaxScale(mManipPart, bbox), LLWorld::getInstance()->getRegionWidthInMeters()); LLVector3 drag_point = gAgent.getPosAgentFromGlobal(mDragPointGlobal); updateGridSettings(); diff --git a/linden/indra/newview/llmaniptranslate.cpp b/linden/indra/newview/llmaniptranslate.cpp index 01fe6f8e1..8484c4ec1 100644 --- a/linden/indra/newview/llmaniptranslate.cpp +++ b/linden/indra/newview/llmaniptranslate.cpp @@ -66,7 +66,7 @@ #include "llui.h" #include "pipeline.h" -#include "hippoLimits.h" +#include "hippolimits.h" // [RLVa:KB] #include "rlvhandler.h" @@ -529,16 +529,13 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) relative_move -= mDragCursorStartGlobal; // You can't move more than some distance from your original mousedown point. - if (gSavedSettings.getBOOL("LimitDragDistance")) - { - F32 max_drag_distance = gSavedSettings.getF32("MaxDragDistance"); + F32 max_drag_distance = gHippoLimits->getMaxDragDistance(); - if (relative_move.magVecSquared() > max_drag_distance * max_drag_distance) - { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (too far)" << llendl; - gViewerWindow->setCursor(UI_CURSOR_NOLOCKED); - return TRUE; - } + if (max_drag_distance != FLT_MAX && relative_move.magVecSquared() > max_drag_distance * max_drag_distance) + { + lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (too far)" << llendl; + gViewerWindow->setCursor(UI_CURSOR_NOLOCKED); + return TRUE; } F64 axis_magnitude = relative_move * axis_d; // dot product diff --git a/linden/indra/newview/llmediactrl.cpp b/linden/indra/newview/llmediactrl.cpp new file mode 100644 index 000000000..8b60326d6 --- /dev/null +++ b/linden/indra/newview/llmediactrl.cpp @@ -0,0 +1,1202 @@ +/** + * @file LLMediaCtrl.cpp + * @brief Web browser UI control + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + + +#include "llmediactrl.h" + +// viewer includes +#include "llfloaterhtml.h" +#include "llfloaterworldmap.h" +#include "lluictrlfactory.h" +#include "llurldispatcher.h" +#include "llurlsimstring.h" +#include "llviewborder.h" +#include "llviewercontrol.h" +#include "llviewermedia.h" +#include "llviewerwindow.h" +#include "llnotifications.h" +#include "llweb.h" +#include "llrender.h" +#include "llpluginclassmedia.h" + +// linden library includes +#include "llfocusmgr.h" + +extern BOOL gRestoreGL; + +// Setting the mozilla buffer width to 2048 exactly doesn't work, since it pads its rowbytes a bit, pushing the texture width over 2048. +// 2000 should give enough headroom for any amount of padding it cares to add. +const S32 MAX_DIMENSION = 2000; +const S32 MAX_TEXTURE_DIMENSION = 2048; + +static LLRegisterWidget<LLMediaCtrl> r("web_browser"); + +LLMediaCtrl::LLMediaCtrl( const std::string& name, const LLRect& rect ) : + LLUICtrl( name, rect, FALSE, NULL, NULL ), + mTextureDepthBytes( 4 ), + mWebBrowserImage( 0 ), + mBorder(NULL), + mFrequentUpdates( true ), + mForceUpdate( false ), + mOpenLinksInExternalBrowser( false ), + mOpenLinksInInternalBrowser( false ), + mTrusted( false ), + mHomePageUrl( "" ), + mIgnoreUIScale( true ), + mAlwaysRefresh( false ), + mExternalUrl( "" ), + mMediaSource( 0 ), + mTakeFocusOnClick( true ), + mCurrentNavUrl( "about:blank" ), + mLastSetCursor( UI_CURSOR_ARROW ), + mStretchToFill( true ), + mMaintainAspectRatio ( true ), + mHideLoading (false) +{ + S32 screen_width = mIgnoreUIScale ? + llround((F32)getRect().getWidth() * LLUI::sGLScaleFactor.mV[VX]) : getRect().getWidth(); + S32 screen_height = mIgnoreUIScale ? + llround((F32)getRect().getHeight() * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight(); + + mMediaSource = LLViewerMedia::newMediaImpl(mHomePageUrl, LLUUID::null, screen_width, screen_height, false, false, "text/html"); + if ( !mMediaSource ) + { + llwarns << "media source create failed " << llendl; + // return; + } + else + { + // create a new texture (based on LLDynamic texture) that will be used to display the output + mWebBrowserImage = new LLWebBrowserTexture( screen_width, screen_height, this, mMediaSource ); + } + + mMediaSource->setVisible( getVisible() ); + + mMediaSource->addObserver( this ); + + LLRect border_rect( 0, getRect().getHeight() + 2, getRect().getWidth() + 2, 0 ); + mBorder = new LLViewBorder( std::string("web control border"), border_rect, LLViewBorder::BEVEL_IN ); + addChild( mBorder ); +} + +//////////////////////////////////////////////////////////////////////////////// +// note: this is now a singleton and destruction happens via initClass() now +LLMediaCtrl::~LLMediaCtrl() +{ + + if (mMediaSource) + { + mMediaSource->remObserver( this ); + mMediaSource = NULL; + } + + if ( mWebBrowserImage ) + { + delete mWebBrowserImage; + mWebBrowserImage = NULL; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::setBorderVisible( BOOL border_visible ) +{ + if ( mBorder ) + { + mBorder->setVisible( border_visible ); + }; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::setTakeFocusOnClick( bool take_focus ) +{ + mTakeFocusOnClick = take_focus; +} + +//////////////////////////////////////////////////////////////////////////////// +// set flag that forces the embedded browser to open links in the external system browser +void LLMediaCtrl::setOpenInExternalBrowser( bool valIn ) +{ + mOpenLinksInExternalBrowser = valIn; +}; + +//////////////////////////////////////////////////////////////////////////////// +// set flag that forces the embedded browser to open links in the internal browser floater +void LLMediaCtrl::setOpenInInternalBrowser( bool valIn ) +{ + mOpenLinksInInternalBrowser = valIn; +}; + +//////////////////////////////////////////////////////////////////////////////// +void LLMediaCtrl::setTrusted( bool valIn ) +{ + mTrusted = valIn; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask ) +{ + convertInputCoords(x, y); + + if (mMediaSource) + mMediaSource->mouseMove(x, y); + + gViewerWindow->setCursor(mLastSetCursor); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks ) +{ + if (mMediaSource && mMediaSource->hasMedia()) + mMediaSource->getMediaPlugin()->scrollEvent(0, clicks, MASK_NONE); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask ) +{ + convertInputCoords(x, y); + + if (mMediaSource) + { + mMediaSource->mouseUp(x, y); + + // *HACK: media_plugin_webkit automatically takes focus on mouseup, + // in addition to the onFocusReceived() call below. Undo this. JC + // IMP-595: Is this really still the case for webkit? + if (!mTakeFocusOnClick) + { + mMediaSource->focus(false); + gViewerWindow->focusClient(); + } + } + + gFocusMgr.setMouseCapture( NULL ); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleMouseDown( S32 x, S32 y, MASK mask ) +{ + convertInputCoords(x, y); + + if (mMediaSource) + mMediaSource->mouseDown(x, y); + + gFocusMgr.setMouseCapture( this ); + + if (mTakeFocusOnClick) + { + setFocus( TRUE ); + } + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleDoubleClick( S32 x, S32 y, MASK mask ) +{ + convertInputCoords(x, y); + + if (mMediaSource) + mMediaSource->mouseLeftDoubleClick( x, y ); + + gFocusMgr.setMouseCapture( this ); + + if (mTakeFocusOnClick) + { + setFocus( TRUE ); + } + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::onFocusReceived() +{ + if (mMediaSource) + { + mMediaSource->focus(true); + + // Set focus for edit menu items + LLEditMenuHandler::gEditMenuHandler = mMediaSource; + } + + LLUICtrl::onFocusReceived(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::onFocusLost() +{ + if (mMediaSource) + { + mMediaSource->focus(false); + + if( LLEditMenuHandler::gEditMenuHandler == mMediaSource ) + { + // Clear focus for edit menu items + LLEditMenuHandler::gEditMenuHandler = NULL; + } + } + + gViewerWindow->focusClient(); + + LLUICtrl::onFocusLost(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask ) +{ + BOOL result = FALSE; + + // FIXME: THIS IS SO WRONG. + // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... + + if (mMediaSource) + { + if( MASK_CONTROL & mask ) + { + if( 'C' == key ) + { + mMediaSource->copy(); + result = TRUE; + } + else + if( 'V' == key ) + { + mMediaSource->paste(); + result = TRUE; + } + else + if( 'X' == key ) + { + mMediaSource->cut(); + result = TRUE; + } + } + + if(!result) + { + result = mMediaSource->handleKeyHere(key, mask); + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::handleVisibilityChange ( BOOL new_visibility ) +{ + llinfos << "visibility changed to " << (new_visibility?"true":"false") << llendl; + if(mMediaSource) + { + mMediaSource->setVisible( new_visibility ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char) +{ + BOOL result = FALSE; + + // only accept 'printable' characters, sigh... + if (uni_char >= 32 // discard 'control' characters + && uni_char != 127) // SDL thinks this is 'delete' - yuck. + { + if (mMediaSource) + result = mMediaSource->handleUnicodeCharHere(uni_char); + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::onVisibilityChange ( BOOL new_visibility ) +{ + // set state of frequent updates automatically if visibility changes + if ( new_visibility ) + { + mFrequentUpdates = true; + } + else + { + mFrequentUpdates = false; + } + LLUICtrl::onVisibilityChange(new_visibility); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::reshape( S32 width, S32 height, BOOL called_from_parent ) +{ + S32 screen_width = mIgnoreUIScale ? llround((F32)width * LLUI::sGLScaleFactor.mV[VX]) : width; + S32 screen_height = mIgnoreUIScale ? llround((F32)height * LLUI::sGLScaleFactor.mV[VY]) : height; + +// llinfos << "reshape called with width = " << width << ", height = " << height << llendl; + + // when floater is minimized, these sizes are negative + if ( mWebBrowserImage && screen_height > 0 && screen_width > 0 ) + { + mWebBrowserImage->resize( screen_width, screen_height ); + mForceUpdate = true; + } + + LLUICtrl::reshape( width, height, called_from_parent ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::navigateBack() +{ + if (mMediaSource && mMediaSource->hasMedia()) + { + mMediaSource->getMediaPlugin()->browse_back(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::navigateForward() +{ + if (mMediaSource && mMediaSource->hasMedia()) + { + mMediaSource->getMediaPlugin()->browse_forward(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLMediaCtrl::canNavigateBack() +{ + if (mMediaSource) + return mMediaSource->canNavigateBack(); + else + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLMediaCtrl::canNavigateForward() +{ + if (mMediaSource) + return mMediaSource->canNavigateForward(); + else + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::set404RedirectUrl( std::string redirect_url ) +{ + if(mMediaSource && mMediaSource->hasMedia()) + mMediaSource->getMediaPlugin()->set_status_redirect( 404, redirect_url ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::clr404RedirectUrl() +{ + if(mMediaSource && mMediaSource->hasMedia()) + mMediaSource->getMediaPlugin()->set_status_redirect(404, ""); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type) +{ + // don't browse to anything that starts with secondlife:// or sl:// + const std::string protocol1 = "secondlife://"; + const std::string protocol2 = "sl://"; + if ((LLStringUtil::compareInsensitive(url_in.substr(0, protocol1.length()), protocol1) == 0) || + (LLStringUtil::compareInsensitive(url_in.substr(0, protocol2.length()), protocol2) == 0)) + { + // TODO: Print out/log this attempt? + // llinfos << "Rejecting attempt to load restricted website :" << urlIn << llendl; + return; + } + + if (mMediaSource) + { + mCurrentNavUrl = url_in; + mMediaSource->navigateTo(url_in, mime_type, mime_type.empty()); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::string& filename_in ) +{ + std::string language = LLUI::getLanguage(); + std::string delim = gDirUtilp->getDirDelimiter(); + std::string filename; + + filename += subdir; + filename += delim; + filename += filename_in; + + std::string expanded_filename = gDirUtilp->findSkinnedFilename("html", language, filename); + + if (! gDirUtilp->fileExists(expanded_filename)) + { + if (language != "en-us") + { + expanded_filename = gDirUtilp->findSkinnedFilename("html", "en-us", filename); + if (! gDirUtilp->fileExists(expanded_filename)) + { + llwarns << "File " << subdir << delim << filename_in << "not found" << llendl; + return; + } + } + else + { + llwarns << "File " << subdir << delim << filename_in << "not found" << llendl; + return; + } + } + if (mMediaSource) + { + mCurrentNavUrl = expanded_filename; + mMediaSource->navigateTo(expanded_filename, "text/html", false); + } + +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::navigateHome() +{ + if( mHomePageUrl.length() ) + { + if (mMediaSource) + mMediaSource->navigateTo(mHomePageUrl); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::setHomePageUrl( const std::string urlIn ) +{ + mHomePageUrl = urlIn; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLMediaCtrl::setCaretColor(unsigned int red, unsigned int green, unsigned int blue) +{ + //NOOP + return false; +} +//////////////////////////////////////////////////////////////////////////////// +// +std::string LLMediaCtrl::getHomePageUrl() +{ + return mHomePageUrl; +} + +//////////////////////////////////////////////////////////////////////////////// +// +LLPluginClassMedia* LLMediaCtrl::getMediaPlugin() +{ + return mMediaSource.isNull() ? NULL : mMediaSource->getMediaPlugin(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::draw() +{ + if ( ! mWebBrowserImage ) + return; + + if ( gRestoreGL == 1 ) + { + LLRect r = getRect(); + reshape( r.getWidth(), r.getHeight(), FALSE ); + return; + }; + + // NOTE: optimization needed here - probably only need to do this once + // unless tearoffs change the parent which they probably do. + const LLUICtrl* ptr = findRootMostFocusRoot(); + if ( ptr && ptr->hasFocus() ) + { + setFrequentUpdates( true ); + } + else + { + setFrequentUpdates( false ); + }; + + // alpha off for this + LLGLSUIDefault gls_ui; + LLGLDisable gls_alphaTest( GL_ALPHA_TEST ); + + gGL.pushMatrix(); + { + if (mIgnoreUIScale) + { + glLoadIdentity(); + // font system stores true screen origin, need to scale this by UI scale factor + // to get render origin for this view (with unit scale) + gGL.translatef(floorf(LLFontGL::sCurOrigin.mX * LLUI::sGLScaleFactor.mV[VX]), + floorf(LLFontGL::sCurOrigin.mY * LLUI::sGLScaleFactor.mV[VY]), + LLFontGL::sCurOrigin.mZ); + } + + // scale texture to fit the space using texture coords + gGL.getTexUnit(0)->bind(mWebBrowserImage->getTexture()); + gGL.color4fv( LLColor4::white.mV ); + F32 max_u = ( F32 )mWebBrowserImage->getMediaWidth() / ( F32 )mWebBrowserImage->getWidth(); + F32 max_v = ( F32 )mWebBrowserImage->getMediaHeight() / ( F32 )mWebBrowserImage->getHeight(); + + LLRect r = getRect(); + S32 width, height; + S32 x_offset = 0; + S32 y_offset = 0; + + if(mStretchToFill) + { + if(mMaintainAspectRatio) + { + F32 media_aspect = (F32)(mWebBrowserImage->getMediaWidth()) / (F32)(mWebBrowserImage->getMediaHeight()); + F32 view_aspect = (F32)(r.getWidth()) / (F32)(r.getHeight()); + if(media_aspect > view_aspect) + { + // max width, adjusted height + width = r.getWidth(); + height = llmin(llmax(S32(width / media_aspect), 0), r.getHeight()); + } + else + { + // max height, adjusted width + height = r.getHeight(); + width = llmin(llmax(S32(height * media_aspect), 0), r.getWidth()); + } + } + else + { + width = r.getWidth(); + height = r.getHeight(); + } + } + else + { + width = llmin(mWebBrowserImage->getMediaWidth(), r.getWidth()); + height = llmin(mWebBrowserImage->getMediaHeight(), r.getHeight()); + } + + x_offset = (r.getWidth() - width) / 2; + y_offset = (r.getHeight() - height) / 2; + + if (mIgnoreUIScale) + { + width = llround((F32)width * LLUI::sGLScaleFactor.mV[VX]); + height = llround((F32)height * LLUI::sGLScaleFactor.mV[VY]); + x_offset = llround((F32)x_offset * LLUI::sGLScaleFactor.mV[VX]); + y_offset = llround((F32)y_offset * LLUI::sGLScaleFactor.mV[VY]); + } + + // draw the browser + gGL.setSceneBlendType(LLRender::BT_REPLACE); + gGL.begin( LLRender::QUADS ); + if (! mWebBrowserImage->getTextureCoordsOpenGL()) + { + // render using web browser reported width and height, instead of trying to invert GL scale + gGL.texCoord2f( max_u, 0.f ); + gGL.vertex2i( x_offset + width, y_offset + height ); + + gGL.texCoord2f( 0.f, 0.f ); + gGL.vertex2i( x_offset, y_offset + height ); + + gGL.texCoord2f( 0.f, max_v ); + gGL.vertex2i( x_offset, y_offset ); + + gGL.texCoord2f( max_u, max_v ); + gGL.vertex2i( x_offset + width, y_offset ); + } + else + { + // render using web browser reported width and height, instead of trying to invert GL scale + gGL.texCoord2f( max_u, max_v ); + gGL.vertex2i( x_offset + width, y_offset + height ); + + gGL.texCoord2f( 0.f, max_v ); + gGL.vertex2i( x_offset, y_offset + height ); + + gGL.texCoord2f( 0.f, 0.f ); + gGL.vertex2i( x_offset, y_offset ); + + gGL.texCoord2f( max_u, 0.f ); + gGL.vertex2i( x_offset + width, y_offset ); + } + gGL.end(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + gGL.popMatrix(); + + // highlight if keyboard focus here. (TODO: this needs some work) + if ( mBorder->getVisible() ) + mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) ); + + + LLUICtrl::draw(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::convertInputCoords(S32& x, S32& y) +{ + x = mIgnoreUIScale ? llround((F32)x * LLUI::sGLScaleFactor.mV[VX]) : x; + if ( ! mWebBrowserImage->getTextureCoordsOpenGL() ) + { + y = mIgnoreUIScale ? llround((F32)(y) * LLUI::sGLScaleFactor.mV[VY]) : y; + } + else + { + y = mIgnoreUIScale ? llround((F32)(getRect().getHeight() - y) * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight() - y; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +bool LLMediaCtrl::onClickLinkExternalTarget(const LLSD& notification, const LLSD& response ) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if ( 0 == option ) + { + // open in external browser because we don't support + // creation of our own secondary browser windows + LLWeb::loadURLExternal( notification["payload"]["external_url"].asString() ); + } + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// inherited from LLViewerMediaObserver +//virtual +void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + switch(event) + { + case MEDIA_EVENT_CONTENT_UPDATED: + { + // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CONTENT_UPDATED " << LL_ENDL; + }; + break; + + case MEDIA_EVENT_TIME_DURATION_UPDATED: + { + // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_SIZE_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_SIZE_CHANGED " << LL_ENDL; + LLRect r = getRect(); + reshape( r.getWidth(), r.getHeight(), FALSE ); + }; + break; + + case MEDIA_EVENT_CURSOR_CHANGED: + { + LL_INFOS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << LL_ENDL; + + std::string cursor = self->getCursorName(); + + if(cursor == "arrow") + mLastSetCursor = UI_CURSOR_ARROW; + else if(cursor == "ibeam") + mLastSetCursor = UI_CURSOR_IBEAM; + else if(cursor == "splith") + mLastSetCursor = UI_CURSOR_SIZEWE; + else if(cursor == "splitv") + mLastSetCursor = UI_CURSOR_SIZENS; + else if(cursor == "hand") + mLastSetCursor = UI_CURSOR_HAND; + else // for anything else, default to the arrow + mLastSetCursor = UI_CURSOR_ARROW; + }; + break; + + case MEDIA_EVENT_NAVIGATE_BEGIN: + { + LL_INFOS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN, url is " << self->getNavigateURI() << LL_ENDL; + if(mMediaSource && mHideLoading) + { + mMediaSource->suspendUpdates(true); + } + }; + break; + + case MEDIA_EVENT_NAVIGATE_COMPLETE: + { + LL_INFOS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << LL_ENDL; + if(mMediaSource && mHideLoading) + { + mMediaSource->suspendUpdates(false); + } + }; + break; + + case MEDIA_EVENT_PROGRESS_UPDATED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << LL_ENDL; + }; + break; + + case MEDIA_EVENT_STATUS_TEXT_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_LOCATION_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_CLICK_LINK_HREF: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL; + onClickLinkHref(self); + }; + break; + + case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << LL_ENDL; + onClickLinkNoFollow(self); + }; + break; + + case MEDIA_EVENT_PLUGIN_FAILED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL; + }; + break; + + case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << LL_ENDL; + }; + break; + + case MEDIA_EVENT_NAME_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAME_CHANGED" << LL_ENDL; + }; + break; + }; + + // chain all events to any potential observers of this object. + emitEvent(self, event); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::onClickLinkHref( LLPluginClassMedia* self ) +{ + // retrieve the event parameters + std::string target = self->getClickTarget(); + std::string url = self->getClickURL(); + + // if there is a value for the target + if ( !target.empty() ) + { + if ( target == "_external" ) + { + mExternalUrl = url; + LLSD payload; + payload["external_url"] = mExternalUrl; + LLNotifications::instance().add( "WebLaunchExternalTarget", LLSD(), payload, onClickLinkExternalTarget); + return; + } + } + + const std::string protocol1( "http://" ); + const std::string protocol2( "https://" ); + if( mOpenLinksInExternalBrowser ) + { + if ( !url.empty() ) + { + if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 || + LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 ) + { + LLWeb::loadURLExternal( url ); + } + } + } + else + if( mOpenLinksInInternalBrowser ) + { + if ( !url.empty() ) + { + if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 || + LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 ) + { + // If we spawn a new LLFloaterHTML, assume we want it to + // follow this LLMediaCtrl's trust for whether or + // not to open secondlife:///app/ links. JC. +// const bool open_links_externally = false; +// LLFloaterHtml::getInstance()->show( +// event_in.mStringPayload, +// "Second Life Browser", +// open_links_externally, +// mTrusted); + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::onClickLinkNoFollow( LLPluginClassMedia* self ) +{ + std::string url = self->getClickURL(); + if (LLURLDispatcher::isSLURLCommand(url) + && !mTrusted) + { + // block handling of this secondlife:///app/ URL + LLNotifications::instance().add("UnableToOpenCommandURL"); + return; + } + + LLURLDispatcher::dispatch(url, this, mTrusted); +} + +//////////////////////////////////////////////////////////////////////////////// +// +LLWebBrowserTexture::LLWebBrowserTexture( S32 width, S32 height, LLMediaCtrl* browserCtrl, viewer_media_t media_source ) : + LLDynamicTexture( 512, 512, 4, ORDER_FIRST, TRUE ), + mNeedsUpdate( true ), + mNeedsResize( false ), + mTextureCoordsOpenGL( true ), + mWebBrowserCtrl( browserCtrl ), + mMediaSource(media_source) +{ + mElapsedTime.start(); + + resize( width, height ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +LLWebBrowserTexture::~LLWebBrowserTexture() +{ + mElapsedTime.stop(); + mMediaSource = NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLWebBrowserTexture::needsRender() +{ + bool texture_dirty = false; + + if ( mWebBrowserCtrl->getFrequentUpdates() || + mWebBrowserCtrl->getAlwaysRefresh() || + mWebBrowserCtrl->getForceUpdate() ) + { + // All of these force an update + return TRUE; + } + + // If the texture needs updating, render needs to be called. + if (mMediaSource && mMediaSource->hasMedia()) + { + LLPluginClassMedia* media = mMediaSource->getMediaPlugin(); + + if(media->textureValid() && media->getDirty()) + { + texture_dirty = true; + } + } + + + return texture_dirty; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLWebBrowserTexture::render() +{ + if(updateBrowserTexture()) + { + // updateBrowserTexture already verified that the media plugin is there and the texture is valid. + LLPluginClassMedia* media_plugin = mMediaSource->getMediaPlugin(); + LLRect dirty_rect; + + if(mNeedsUpdate) + { + // If we need an update, use the whole rect instead of the dirty rect. + dirty_rect.mLeft = 0; + dirty_rect.mBottom = 0; + dirty_rect.mRight = media_plugin->getWidth(); + dirty_rect.mTop = media_plugin->getHeight(); + } + else + { + mNeedsUpdate = media_plugin->getDirty(&dirty_rect); + } + + if ( mNeedsUpdate ) + { + mNeedsUpdate = false; + mWebBrowserCtrl->setForceUpdate(false); + + // Constrain the dirty rect to be inside the texture + S32 x_pos = llmax(dirty_rect.mLeft, 0); + S32 y_pos = llmax(dirty_rect.mBottom, 0); + S32 width = llmin(dirty_rect.mRight, getWidth()) - x_pos; + S32 height = llmin(dirty_rect.mTop, getHeight()) - y_pos; + + if(width > 0 && height > 0) + { + U8* data = media_plugin->getBitsData(); + + // Offset the pixels pointer to match x_pos and y_pos + data += ( x_pos * media_plugin->getTextureDepth() * media_plugin->getBitsWidth() ); + data += ( y_pos * media_plugin->getTextureDepth() ); + + mTexture->setSubImage( + data, + media_plugin->getBitsWidth(), + media_plugin->getBitsHeight(), + x_pos, + y_pos, + width, + height, + TRUE); // force a fast update (i.e. don't call analyzeAlpha, etc.) + } + + media_plugin->resetDirty(); + + return TRUE; + }; + }; + + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +S32 LLWebBrowserTexture::getMediaWidth() +{ + return mMediaWidth; +} + +//////////////////////////////////////////////////////////////////////////////// +// +S32 LLWebBrowserTexture::getMediaHeight() +{ + return mMediaHeight; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLWebBrowserTexture::setNeedsUpdate() +{ + mNeedsUpdate = true; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLWebBrowserTexture::getNeedsUpdate() +{ + return mNeedsUpdate; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLWebBrowserTexture::getTextureCoordsOpenGL() +{ + return mTextureCoordsOpenGL; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +void LLWebBrowserTexture::resize( S32 new_width, S32 new_height ) +{ + F32 scale_ratio = 1.f; + if (new_width > MAX_DIMENSION) + { + scale_ratio = (F32)MAX_DIMENSION / (F32)new_width; + } + if (new_height > MAX_DIMENSION) + { + scale_ratio = llmin(scale_ratio, (F32)MAX_DIMENSION / (F32)new_height); + } + + mMediaWidth = llround(scale_ratio * (F32)new_width); + mMediaHeight = llround(scale_ratio * (F32)new_height); + + adjustSize(); +} + +bool LLWebBrowserTexture::adjustSize() +{ + if (mMediaSource && mMediaSource->hasMedia()) + { + int natural_width = mMediaSource->getMediaPlugin()->getNaturalWidth(); + int natural_height = mMediaSource->getMediaPlugin()->getNaturalHeight(); + + if(natural_width != 0) + { + // If the media has a "natural size", use it. + mMediaWidth = natural_width; + mMediaHeight = natural_height; + } + + mMediaSource->setSize(mMediaWidth, mMediaHeight); + mNeedsResize = false; + + return true; + } + else + { + // The media isn't fully initialized yet, delay the resize until later. + mNeedsResize = true; + } + + return false; +} + +bool LLWebBrowserTexture::updateBrowserTexture() +{ + if (!adjustSize()) + return false; + + LLPluginClassMedia* media = mMediaSource->getMediaPlugin(); + + if(!media->textureValid()) + return false; + + if(mMediaSource->mNeedsNewTexture + || media->getTextureWidth() != mWidth + || media->getTextureHeight() != mHeight ) + { + releaseGLTexture(); + + mWidth = media->getTextureWidth(); + mHeight = media->getTextureHeight(); + mTextureCoordsOpenGL = media->getTextureCoordsOpenGL(); + + // will create mWidth * mHeight sized texture, using the texture params specified by the media. + LLDynamicTexture::generateGLTexture( + media->getTextureFormatInternal(), + media->getTextureFormatPrimary(), + media->getTextureFormatType(), + media->getTextureFormatSwapBytes()); + + + mMediaSource->mNeedsNewTexture = false; + } + + return true; +} +// virtual +LLXMLNodePtr LLMediaCtrl::getXML(bool save_children) const +{ + LLXMLNodePtr node = LLUICtrl::getXML(); + + node->setName(LL_WEB_BROWSER_CTRL_TAG); + + return node; +} + +LLView* LLMediaCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +{ + std::string name("web_browser"); + node->getAttributeString("name", name); + + std::string start_url(""); + node->getAttributeString("start_url", start_url ); + + BOOL border_visible = true; + node->getAttributeBOOL("border_visible", border_visible); + + LLRect rect; + createRect(node, rect, parent, LLRect()); + + LLMediaCtrl* web_browser = new LLMediaCtrl( name, rect ); + + if(node->hasAttribute("caret_color")) + { + LLColor4 color; + LLUICtrlFactory::getAttributeColor(node, "caret_color", color); + LLColor4U colorU = LLColor4U(color); + web_browser->setCaretColor( colorU.mV[0], colorU.mV[1], colorU.mV[2] ); + } + + BOOL ignore_ui_scale = web_browser->getIgnoreUIScale(); + node->getAttributeBOOL("ignore_ui_scale", ignore_ui_scale); + web_browser->setIgnoreUIScale((bool)ignore_ui_scale); + + web_browser->initFromXML(node, parent); + + web_browser->setHomePageUrl( start_url ); + + web_browser->setBorderVisible( border_visible ); + + if(! start_url.empty()) + { + web_browser->navigateHome(); + } + + return web_browser; +} + +std::string LLMediaCtrl::getCurrentNavUrl() +{ + return mCurrentNavUrl; +} + diff --git a/linden/indra/newview/llwebbrowserctrl.h b/linden/indra/newview/llmediactrl.h similarity index 53% rename from linden/indra/newview/llwebbrowserctrl.h rename to linden/indra/newview/llmediactrl.h index 010080734..77f59c7e7 100644 --- a/linden/indra/newview/llwebbrowserctrl.h +++ b/linden/indra/newview/llmediactrl.h @@ -1,5 +1,5 @@ /** - * @file llwebbrowserctrl.h + * @file llmediactrl.h * @brief Web browser UI control * * $LicenseInfo:firstyear=2006&license=viewergpl$ @@ -30,158 +30,29 @@ * $/LicenseInfo$ */ -#ifndef LL_LLWEBBROWSERCTRL_H -#define LL_LLWEBBROWSERCTRL_H +#ifndef LL_LLMediaCtrl_H +#define LL_LLMediaCtrl_H -//////////////////////////////////////////////////////////////////////////////// -// data class that is passed with an event -class LLWebBrowserCtrlEvent -{ - public: - LLWebBrowserCtrlEvent() - { - }; - - LLWebBrowserCtrlEvent( int intValIn ) : - mIntVal( intValIn ) - { - }; - - LLWebBrowserCtrlEvent( std::string stringValIn ) : - mIntVal(-1), - mStringVal( stringValIn ) - { - }; - - LLWebBrowserCtrlEvent( std::string stringValIn, std::string stringValExIn ) : - mIntVal(-1), - mStringVal( stringValIn ), - mStringValEx( stringValExIn ) - { - }; - - virtual ~LLWebBrowserCtrlEvent() - { - }; - - int getIntValue() const - { - return mIntVal; - }; - - std::string getStringValue() const - { - return mStringVal; - }; - - std::string getStringValueEx() const - { - return mStringValEx; - }; - - private: - int mIntVal; - std::string mStringVal; - std::string mStringValEx; -}; - -//////////////////////////////////////////////////////////////////////////////// -// Override these methods to observe web browser control events -// (they are chained and fired after observing LLMozLibEvents) -class LLWebBrowserCtrlObserver -{ - public: - virtual ~LLWebBrowserCtrlObserver() { }; - - typedef LLWebBrowserCtrlEvent EventType; - virtual void onNavigateBegin( const EventType& eventIn ) { }; - virtual void onNavigateComplete( const EventType& eventIn ) { }; - virtual void onUpdateProgress( const EventType& eventIn ) { }; - virtual void onStatusTextChange( const EventType& eventIn ) { }; - virtual void onLocationChange( const EventType& eventIn ) { }; - virtual void onClickLinkHref( const EventType& eventIn ) { }; - virtual void onClickLinkNoFollow( const EventType& eventIn ) { }; -}; +#include "llviewermedia.h" #include "lluictrl.h" #include "llframetimer.h" #include "lldynamictexture.h" -#include "llmediamanager.h" -#include "llmediaobserver.h" class LLViewBorder; class LLWebBrowserTexture; - -/////////////////////////////////////////////////////////////////////////////// -// manages the process of storing and emitting events that the consumer -// of the embedding class can observe -template< class T > -class LLWebBrowserCtrlEventEmitter -{ - public: - LLWebBrowserCtrlEventEmitter() { }; - ~LLWebBrowserCtrlEventEmitter() { }; - - typedef typename T::EventType EventType; - typedef std::list< T* > ObserverContainer; - typedef void( T::*observerMethod )( const EventType& ); - - /////////////////////////////////////////////////////////////////////////////// - // - bool addObserver( T* observerIn ) - { - if ( ! observerIn ) - return false; - - if ( std::find( observers.begin(), observers.end(), observerIn ) != observers.end() ) - return false; - - observers.push_back( observerIn ); - - return true; - }; - - /////////////////////////////////////////////////////////////////////////////// - // - bool remObserver( T* observerIn ) - { - if ( ! observerIn ) - return false; - - observers.remove( observerIn ); - - return true; - }; - - /////////////////////////////////////////////////////////////////////////////// - // - void update( observerMethod method, const EventType& msgIn ) - { - typename std::list< T* >::iterator iter = observers.begin(); - - while( iter != observers.end() ) - { - ( ( *iter )->*method )( msgIn ); - - ++iter; - }; - }; - - protected: - ObserverContainer observers; -}; - class LLUICtrlFactory; //////////////////////////////////////////////////////////////////////////////// // -class LLWebBrowserCtrl : +class LLMediaCtrl : public LLUICtrl, - public LLMediaObserver + public LLViewerMediaObserver, + public LLViewerMediaEventEmitter { public: - LLWebBrowserCtrl( const std::string& name, const LLRect& rect ); - virtual ~LLWebBrowserCtrl(); + LLMediaCtrl( const std::string& name, const LLRect& rect ); + virtual ~LLMediaCtrl(); void setBorderVisible( BOOL border_visible ); @@ -202,7 +73,7 @@ class LLWebBrowserCtrl : virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); // navigation - void navigateTo( std::string urlIn ); + void navigateTo( std::string url_in, std::string mime_type = ""); void navigateBack(); void navigateHome(); void navigateForward(); @@ -225,8 +96,8 @@ class LLWebBrowserCtrl : std::string getHomePageUrl(); // set/clear URL to visit when a 404 page is reached - bool set404RedirectUrl( std::string redirect_url ); - bool clr404RedirectUrl(); + void set404RedirectUrl( std::string redirect_url ); + void clr404RedirectUrl(); // accessor/mutator for flag that indicates if frequent updates to texture happen bool getFrequentUpdates() { return mFrequentUpdates; }; @@ -241,11 +112,14 @@ class LLWebBrowserCtrl : void setForceUpdate(bool force_update) { mForceUpdate = force_update; } bool getForceUpdate() { return mForceUpdate; } + LLPluginClassMedia* getMediaPlugin(); + bool setCaretColor( unsigned int red, unsigned int green, unsigned int blue ); // over-rides virtual BOOL handleKeyHere( KEY key, MASK mask); + virtual void handleVisibilityChange ( BOOL new_visibility ); virtual BOOL handleUnicodeCharHere(llwchar uni_char); virtual void reshape( S32 width, S32 height, BOOL called_from_parent = TRUE); virtual void draw(); @@ -254,30 +128,21 @@ class LLWebBrowserCtrl : // focus overrides void onFocusLost(); void onFocusReceived(); + + // Incoming media event dispatcher + virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); - // observer interface - bool addObserver( LLWebBrowserCtrlObserver* subjectIn ); - bool remObserver( LLWebBrowserCtrlObserver* subjectIn ); - - // LLMozlib observer overrides - virtual void onNavigateBegin( const EventType& eventIn ); - virtual void onNavigateComplete( const EventType& eventIn ); - virtual void onUpdateProgress( const EventType& eventIn ); - virtual void onStatusTextChange( const EventType& eventIn ); - virtual void onLocationChange( const EventType& eventIn ); - virtual void onClickLinkHref( const EventType& eventIn ); - virtual void onClickLinkNoFollow( const EventType& eventIn ); - virtual void onMediaContentsChange( const EventType& event_in ); - + // handlers for individual events (could be done inside the switch in handleMediaEvent, they're just individual functions for clarity) + void onClickLinkHref( LLPluginClassMedia* self ); + void onClickLinkNoFollow( LLPluginClassMedia* self ); + protected: void convertInputCoords(S32& x, S32& y); private: static bool onClickLinkExternalTarget( const LLSD&, const LLSD& ); - LLWebBrowserCtrlEventEmitter< LLWebBrowserCtrlObserver > mEventEmitter; const S32 mTextureDepthBytes; - int mEmbeddedBrowserWindowId; LLWebBrowserTexture* mWebBrowserImage; LLViewBorder* mBorder; bool mFrequentUpdates; @@ -290,16 +155,21 @@ class LLWebBrowserCtrl : std::string mCurrentNavUrl; bool mIgnoreUIScale; bool mAlwaysRefresh; - LLMediaBase* mMediaSource; + viewer_media_t mMediaSource; bool mTakeFocusOnClick; + ECursorType mLastSetCursor; + bool mStretchToFill; + bool mMaintainAspectRatio; + bool mHideLoading; }; //////////////////////////////////////////////////////////////////////////////// // class LLWebBrowserTexture : public LLDynamicTexture { +LOG_CLASS(LLWebBrowserTexture); public: - LLWebBrowserTexture( S32 width, S32 height, LLWebBrowserCtrl* browserCtrl, LLMediaBase *media_source ); + LLWebBrowserTexture( S32 width, S32 height, LLMediaCtrl* browserCtrl, viewer_media_t media_source ); virtual ~LLWebBrowserTexture(); virtual BOOL needsRender(); @@ -307,20 +177,25 @@ class LLWebBrowserTexture : public LLDynamicTexture virtual void postRender( BOOL success ) {}; virtual BOOL render(); - S32 getBrowserWidth(); - S32 getBrowserHeight(); + bool adjustSize(); + S32 getMediaWidth(); + S32 getMediaHeight(); + bool getNeedsUpdate(); void setNeedsUpdate(); + bool getTextureCoordsOpenGL(); void resize( S32 new_width, S32 new_height ); + bool updateBrowserTexture(); protected: - S32 mBrowserWidth; - S32 mBrowserHeight; - S32 mLastBrowserDepth; + S32 mMediaWidth; + S32 mMediaHeight; bool mNeedsUpdate; + bool mNeedsResize; + bool mTextureCoordsOpenGL; LLFrameTimer mElapsedTime; - LLWebBrowserCtrl* mWebBrowserCtrl; - LLMediaBase *mMediaSource; + LLMediaCtrl* mWebBrowserCtrl; + viewer_media_t mMediaSource; }; -#endif // LL_LLWEBBROWSERCTRL_H +#endif // LL_LLMediaCtrl_H diff --git a/linden/indra/newview/llmediaremotectrl.cpp b/linden/indra/newview/llmediaremotectrl.cpp index 67cb75819..48715fcad 100644 --- a/linden/indra/newview/llmediaremotectrl.cpp +++ b/linden/indra/newview/llmediaremotectrl.cpp @@ -34,7 +34,7 @@ #include "llmediaremotectrl.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "lliconctrl.h" #include "llmimetypes.h" #include "lloverlaybar.h" @@ -86,6 +86,7 @@ BOOL LLMediaRemoteCtrl::postBuild() childSetAction("media_stop",LLOverlayBar::mediaStop,this); childSetAction("music_stop",LLOverlayBar::toggleMusicPlay,this); childSetAction("media_pause",LLOverlayBar::toggleMediaPlay,this); + childSetAction("music_pause",LLOverlayBar::toggleMusicPlay,this); childSetAction("expand", onClickExpandBtn, this); return TRUE; @@ -135,9 +136,11 @@ void* LLMediaRemoteCtrl::createVolumePanel(void* data) // Virtual void LLMediaRemoteCtrl::setToolTip(const std::string& msg) { - std::string mime_type = LLMIMETypes::translate(LLViewerMedia::getMimeType()); - std::string tool_tip = LLMIMETypes::findToolTip(LLViewerMedia::getMimeType()); - std::string play_tip = LLMIMETypes::findPlayTip(LLViewerMedia::getMimeType()); + // TODO: this gets removed for Media on a Prim + + const std::string mime_type = LLViewerParcelMedia::getMimeType(); + std::string tool_tip = LLMIMETypes::findToolTip(mime_type); + std::string play_tip = LLMIMETypes::findPlayTip(mime_type); // childSetToolTip("media_stop", mControls->getString("stop_label") + "\n" + tool_tip); childSetToolTip("media_icon", tool_tip); childSetToolTip("media_play", play_tip); @@ -150,6 +153,7 @@ void LLMediaRemoteCtrl::enableMediaButtons() bool stop_media_enabled = false; bool play_music_enabled = false; bool stop_music_enabled = false; + bool music_show_pause = false; bool media_show_pause = false; static LLColor4* sIconDisabledColor = rebind_llcontrol<LLColor4>("IconDisabledColor", &gColors, true); @@ -174,23 +178,22 @@ void LLMediaRemoteCtrl::enableMediaButtons() play_media_enabled = true; media_icon_color = LLUI::sColorsGroup->getColor( "IconEnabledColor" ); - LLMediaBase::EStatus status = LLViewerParcelMedia::getStatus(); + LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getStatus(); switch(status) { - case LLMediaBase::STATUS_STOPPED: - case LLMediaBase::STATUS_UNKNOWN: + case LLViewerMediaImpl::MEDIA_NONE: media_show_pause = false; stop_media_enabled = false; break; - case LLMediaBase::STATUS_STARTED: - case LLMediaBase::STATUS_NAVIGATING: - case LLMediaBase::STATUS_RESETTING: + case LLViewerMediaImpl::MEDIA_LOADING: + case LLViewerMediaImpl::MEDIA_LOADED: + case LLViewerMediaImpl::MEDIA_PLAYING: // HACK: only show the pause button for movie types media_show_pause = LLMIMETypes::widgetType(parcel->getMediaType()) == "movie" ? true : false; stop_media_enabled = true; play_media_enabled = false; break; - case LLMediaBase::STATUS_PAUSED: + case LLViewerMediaImpl::MEDIA_PAUSED: media_show_pause = false; stop_media_enabled = true; break; @@ -205,41 +208,37 @@ void LLMediaRemoteCtrl::enableMediaButtons() { if ( parcel && !parcel->getMusicURL().empty()) { + play_music_enabled = true; music_icon_color = LLUI::sColorsGroup->getColor( "IconEnabledColor" ); if (gOverlayBar->musicPlaying()) { - play_music_enabled = false; + music_show_pause = true; stop_music_enabled = true; } else { - play_music_enabled = true; + music_show_pause = false; stop_music_enabled = false; } } - // if no mime type has been set disable play - if( LLViewerMedia::getMimeType().empty() - || LLViewerMedia::getMimeType() == "none/none") - { - play_media_enabled = false; - stop_media_enabled = false; - } + // Don't test the mime-type: this is not updated in a consistent basis. The existence of a valid gAudiop is enough guarantee. } const std::string media_icon_name = LLMIMETypes::findIcon(media_type); - LLButton* music_play_btn = getChild<LLButton>("music_play"); LLButton* music_stop_btn = getChild<LLButton>("music_stop"); - - music_play_btn->setEnabled(play_music_enabled); - music_stop_btn->setEnabled(stop_music_enabled); - childSetColor("music_icon", music_icon_color); - + LLButton* music_pause_btn = getChild<LLButton>("music_pause"); LLButton* media_play_btn = getChild<LLButton>("media_play"); LLButton* media_stop_btn = getChild<LLButton>("media_stop"); LLButton* media_pause_btn = getChild<LLButton>("media_pause"); LLIconCtrl* media_icon = getChild<LLIconCtrl>("media_icon"); + music_play_btn->setEnabled(play_music_enabled); + music_stop_btn->setEnabled(stop_music_enabled); + music_pause_btn->setEnabled(music_show_pause); + music_pause_btn->setVisible(music_show_pause); + music_play_btn->setVisible(! music_show_pause); + childSetColor("music_icon", music_icon_color); if(!media_icon_name.empty()) { media_icon->setImage(media_icon_name); diff --git a/linden/indra/newview/llmimetypes.cpp b/linden/indra/newview/llmimetypes.cpp index bfbc81aa6..c45e0abf5 100644 --- a/linden/indra/newview/llmimetypes.cpp +++ b/linden/indra/newview/llmimetypes.cpp @@ -46,6 +46,8 @@ std::string sDefaultWidgetType; // Returned when we don't know what widget set to use std::string sDefaultImpl; // Returned when we don't know what impl to use +std::string sXMLFilename; + // Squirrel away XML filename so we know how to reset ///////////////////////////////////////////////////////////////////////////// @@ -54,6 +56,24 @@ bool LLMIMETypes::parseMIMETypes(const std::string& xml_filename) { LLXMLNodePtr root; bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); + + if (!success) + { + // If fails, check if we can read the file from the app_settings folder + std::string settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, xml_filename); + success = LLUICtrlFactory::getLayeredXMLNode(settings_filename, root); + + #if LL_WINDOWS + // On the windows dev builds, unpackaged, the mime_types.xml file will be located in + // indra/build-vc**/newview/<config>/app_settings. + if (!success) + { + settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", xml_filename); + success = LLUICtrlFactory::getLayeredXMLNode(settings_filename, root); + } + #endif + } + if ( ! success || root.isNull() || ! root->hasName( "mimetypes" ) ) { llwarns << "Unable to read MIME type file: " @@ -146,6 +166,8 @@ bool LLMIMETypes::parseMIMETypes(const std::string& xml_filename) sWidgetMap[set_name] = info; } } + + sXMLFilename = xml_filename; return true; } @@ -267,3 +289,23 @@ bool LLMIMETypes::findAllowLooping(const std::string& mime_type) } return allow_looping; } + +// static +bool LLMIMETypes::isTypeHandled(const std::string& mime_type) +{ + mime_info_map_t::const_iterator it = sMap.find(mime_type); + if (it != sMap.end()) + { + return true; + } + return false; +} + +// static +void LLMIMETypes::reload(void*) +{ + sMap.clear(); + sWidgetMap.clear(); + (void)LLMIMETypes::parseMIMETypes(sXMLFilename); +} + diff --git a/linden/indra/newview/llmimetypes.h b/linden/indra/newview/llmimetypes.h index 7a50c2942..b217ce7a8 100644 --- a/linden/indra/newview/llmimetypes.h +++ b/linden/indra/newview/llmimetypes.h @@ -72,6 +72,12 @@ class LLMIMETypes static bool findAllowLooping(const std::string& mime_type); // accessor for flag to enable/disable media looping checkbox + static bool isTypeHandled(const std::string& mime_type); + // determines if the specific mime type is handled by the media system + + static void reload(void*); + // re-loads the MIME types file from the file path last passed into parseMIMETypes + public: struct LLMIMEInfo { diff --git a/linden/indra/newview/llmutelist.cpp b/linden/indra/newview/llmutelist.cpp index 0e03509eb..fff555842 100644 --- a/linden/indra/newview/llmutelist.cpp +++ b/linden/indra/newview/llmutelist.cpp @@ -265,7 +265,7 @@ LLMuteList::~LLMuteList() // If we quit from the login screen we will not have an SL account // name. Don't try to save, otherwise we'll dump a file in // C:\Program Files\SecondLife\ JC - std::string user_dir = gDirUtilp->getLindenUserDir(); + std::string user_dir = gDirUtilp->getLindenUserDir(true); if (!user_dir.empty()) { std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "volume_settings.xml"); diff --git a/linden/indra/newview/llnamelistctrl.cpp b/linden/indra/newview/llnamelistctrl.cpp index 453cf7fab..e445df54c 100644 --- a/linden/indra/newview/llnamelistctrl.cpp +++ b/linden/indra/newview/llnamelistctrl.cpp @@ -72,7 +72,7 @@ LLNameListCtrl::~LLNameListCtrl() // public BOOL LLNameListCtrl::addNameItem(const LLUUID& agent_id, EAddPosition pos, - BOOL enabled, std::string& suffix) + BOOL enabled, const std::string& suffix) { //llinfos << "LLNameListCtrl::addNameItem " << agent_id << llendl; diff --git a/linden/indra/newview/llnamelistctrl.h b/linden/indra/newview/llnamelistctrl.h index 1b7795ddf..beb4ede83 100644 --- a/linden/indra/newview/llnamelistctrl.h +++ b/linden/indra/newview/llnamelistctrl.h @@ -58,7 +58,7 @@ class LLNameListCtrl // Add a user to the list by name. It will be added, the name // requested from the cache, and updated as necessary. BOOL addNameItem(const LLUUID& agent_id, EAddPosition pos = ADD_BOTTOM, - BOOL enabled = TRUE, std::string& suffix = LLStringUtil::null); + BOOL enabled = TRUE, const std::string& suffix = LLStringUtil::null); BOOL addNameItem(LLScrollListItem* item, EAddPosition pos = ADD_BOTTOM); virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL); diff --git a/linden/indra/newview/llnetmap.cpp b/linden/indra/newview/llnetmap.cpp index dc4456aa5..b9dc482ba 100644 --- a/linden/indra/newview/llnetmap.cpp +++ b/linden/indra/newview/llnetmap.cpp @@ -71,7 +71,7 @@ #include "llglheaders.h" -#include "hippoLimits.h" +#include "hippolimits.h" // [RLVa:KB] #include "rlvhandler.h" diff --git a/linden/indra/newview/llnotify.cpp b/linden/indra/newview/llnotify.cpp index b0f5f9149..891707b90 100644 --- a/linden/indra/newview/llnotify.cpp +++ b/linden/indra/newview/llnotify.cpp @@ -55,7 +55,7 @@ #include "lloverlaybar.h" // for gOverlayBar #include "lluictrlfactory.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // [RLVa:KB] - Version: 1.23.4 #include "rlvhandler.h" diff --git a/linden/indra/newview/lloverlaybar.cpp b/linden/indra/newview/lloverlaybar.cpp index 5ca590580..ed406e853 100644 --- a/linden/indra/newview/lloverlaybar.cpp +++ b/linden/indra/newview/lloverlaybar.cpp @@ -38,12 +38,12 @@ #include "lloverlaybar.h" #include "aoremotectrl.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llrender.h" #include "llagent.h" #include "llbutton.h" #include "llchatbar.h" -#include "llfloaterchat.h" +//#include "llfloaterchat.h" #include "llfocusmgr.h" #include "llimview.h" #include "llmediaremotectrl.h" @@ -63,7 +63,7 @@ #include "llvoiceclient.h" #include "llvoavatar.h" #include "llvoiceremotectrl.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" #include "llwindlightremotectrl.h" #include "llselectmgr.h" @@ -79,59 +79,10 @@ LLOverlayBar *gOverlayBar = NULL; extern S32 MENU_BAR_HEIGHT; - -class LLTitleObserver - : public LLMediaObserver -{ -public: - void init(std::string url); - /*virtual*/ void onMediaTitleChange(const EventType& event_in); -private: - LLMediaBase* mMediaSource; -}; - -static LLTitleObserver sTitleObserver; - -static LLRegisterWidget<LLMediaRemoteCtrl> r("media_remote"); - -void LLTitleObserver::init(std::string url) -{ - - if (!gAudiop) - { - return; - } - - mMediaSource = gAudiop->getStreamMedia(); // LLViewerMedia::getSource(); - - if ( mMediaSource ) - { - mMediaSource->addObserver(this); - } -} - -//virtual -void LLTitleObserver::onMediaTitleChange(const EventType& event_in) -{ - if ( !gSavedSettings.getBOOL("ShowStreamTitle") ) - { - return; - } - - LLChat chat; - //TODO: set this in XUI - std::string playing_msg = "Playing: " + event_in.getStringValue(); - chat.mText = playing_msg; - LLFloaterChat::addChat(chat, FALSE, FALSE); -} - - // // Functions // - - void* LLOverlayBar::createMediaRemote(void* userdata) { LLOverlayBar *self = (LLOverlayBar*)userdata; @@ -452,11 +403,11 @@ void LLOverlayBar::toggleMediaPlay(void*) } - if (LLViewerMedia::isMediaPaused()) + if (LLViewerParcelMedia::getStatus() == LLViewerMediaImpl::MEDIA_PAUSED) { LLViewerParcelMedia::start(); } - else if(LLViewerMedia::isMediaPlaying()) + else if(LLViewerParcelMedia::getStatus() == LLViewerMediaImpl::MEDIA_PLAYING) { LLViewerParcelMedia::pause(); } @@ -497,7 +448,7 @@ void LLOverlayBar::toggleMusicPlay(void*) // if ( gAudiop->isInternetStreamPlaying() == 0 ) { gAudiop->startInternetStream(parcel->getMusicURL()); - sTitleObserver.init(parcel->getMusicURL()); +//awfixme sTitleObserver.init(parcel->getMusicURL()); } } } diff --git a/linden/indra/newview/llpanelaudioprefs.cpp b/linden/indra/newview/llpanelaudioprefs.cpp index 2bb3ab406..1acfcbb44 100644 --- a/linden/indra/newview/llpanelaudioprefs.cpp +++ b/linden/indra/newview/llpanelaudioprefs.cpp @@ -42,7 +42,7 @@ #include "llfontgl.h" // project includes -#include "audioengine.h" +#include "llaudioengine.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" @@ -62,7 +62,7 @@ #include "llviewerwindow.h" #include "llviewercontrol.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // // Static functions @@ -105,7 +105,6 @@ void LLPanelAudioPrefs::refreshValues() mPreviousMusicVolume = gSavedSettings.getF32("AudioLevelMusic"); mPreviousMediaVolume = gSavedSettings.getF32("AudioLevelMedia"); mPreviousDoppler = gSavedSettings.getF32("AudioLevelDoppler"); - mPreviousDistance = gSavedSettings.getF32("AudioLevelDistance"); mPreviousRolloff = gSavedSettings.getF32("AudioLevelRolloff"); mPreviousMoneyThreshold = gSavedSettings.getF32("UISndMoneyChangeThreshold"); @@ -134,7 +133,6 @@ void LLPanelAudioPrefs::cancel() gSavedSettings.setF32("AudioLevelMusic", mPreviousMusicVolume); gSavedSettings.setF32("AudioLevelMedia", mPreviousMediaVolume); gSavedSettings.setF32("AudioLevelDoppler", mPreviousDoppler ); - gSavedSettings.setF32("AudioLevelDistance", mPreviousDistance ); gSavedSettings.setF32("AudioLevelRolloff", mPreviousRolloff ); gSavedSettings.setF32("UISndMoneyChangeThreshold", mPreviousMoneyThreshold ); diff --git a/linden/indra/newview/llpanelavatar.cpp b/linden/indra/newview/llpanelavatar.cpp index f4501becf..6110e4410 100644 --- a/linden/indra/newview/llpanelavatar.cpp +++ b/linden/indra/newview/llpanelavatar.cpp @@ -64,6 +64,7 @@ #include "llmutelist.h" #include "llpanelclassified.h" #include "llpanelpick.h" +#include "llpluginclassmedia.h" #include "llscrolllistctrl.h" #include "llstatusbar.h" #include "lltabcontainer.h" @@ -414,14 +415,13 @@ BOOL LLPanelAvatarWeb::postBuild(void) childSetControlName("auto_load","AutoLoadWebProfiles"); - mWebBrowser = getChild<LLWebBrowserCtrl>("profile_html"); + mWebBrowser = getChild<LLMediaCtrl>("profile_html"); + + mWebBrowser->addObserver(this); // links open in internally mWebBrowser->setOpenInExternalBrowser( false ); - // observe browser events - mWebBrowser->addObserver( this ); - return TRUE; } @@ -480,18 +480,32 @@ LLPanelAvatarWeb::LLPanelAvatarWeb(const std::string& name, const LLRect& rect, LLPanelAvatarWeb::~LLPanelAvatarWeb() { - // stop observing browser events - if ( mWebBrowser ) +} + +void LLPanelAvatarWeb::refresh() +{ + if (mNavigateTo != "") { - mWebBrowser->remObserver( this ); - }; + llinfos << "Loading " << mNavigateTo << llendl; + mWebBrowser->navigateTo( mNavigateTo ); + mNavigateTo = ""; + } +} +void LLPanelAvatarWeb::onVisibilityChange(BOOL new_visibility) +{ + LLPluginClassMedia::EPriority new_priority; + + if (new_visibility) + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + else + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + + mWebBrowser->getMediaPlugin()->setPriority(new_priority); } void LLPanelAvatarWeb::enableControls(BOOL self) { childSetEnabled("url_edit",self); - childSetVisible("status_text",!self && !mHome.empty()); - childSetText("status_text", LLStringUtil::null); } void LLPanelAvatarWeb::setWebURL(std::string url) @@ -515,11 +529,8 @@ void LLPanelAvatarWeb::setWebURL(std::string url) else { childSetVisible("profile_html",false); + childSetVisible("status_text", false); } - - BOOL own_avatar = (getPanelAvatar()->getAvatarID() == gAgent.getID() ); - childSetVisible("status_text",!own_avatar && !mHome.empty()); - } // static @@ -542,13 +553,15 @@ void LLPanelAvatarWeb::load(std::string url) { bool have_url = (!url.empty()); + + childSetVisible("profile_html", have_url); + childSetVisible("status_text", have_url); + childSetText("status_text", LLStringUtil::null); + if (have_url) { - llinfos << "Loading " << url << llendl; - mWebBrowser->navigateTo( url ); + mNavigateTo = url; } - - childSetVisible("profile_html", have_url); } //static @@ -590,14 +603,22 @@ void LLPanelAvatarWeb::onCommitLoad(LLUICtrl* ctrl, void* data) } } -void LLPanelAvatarWeb::onStatusTextChange( const EventType& eventIn ) +void LLPanelAvatarWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) { - childSetText("status_text", eventIn.getStringValue() ); -} - -void LLPanelAvatarWeb::onLocationChange( const EventType& eventIn ) -{ - childSetText("url_edit", eventIn.getStringValue() ); + switch(event) + { + case MEDIA_EVENT_STATUS_TEXT_CHANGED: + childSetText("status_text", self->getStatusText() ); + break; + + case MEDIA_EVENT_LOCATION_CHANGED: + childSetText("url_edit", self->getLocation() ); + break; + + default: + // Having a default case makes the compiler happy. + break; + } } diff --git a/linden/indra/newview/llpanelavatar.h b/linden/indra/newview/llpanelavatar.h index 72a47f579..9a2f450e7 100644 --- a/linden/indra/newview/llpanelavatar.h +++ b/linden/indra/newview/llpanelavatar.h @@ -36,7 +36,7 @@ #include "llpanel.h" #include "v3dmath.h" #include "lluuid.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" class LLButton; class LLCheckBoxCtrl; @@ -55,7 +55,7 @@ class LLViewerImage; class LLViewerObject; class LLMessageSystem; class LLIconCtrl; -class LLWebBrowserCtrl; +class LLMediaCtrl; enum EOnlineStatus { @@ -76,7 +76,6 @@ class LLPanelAvatarTab : public LLPanel /*virtual*/ void draw(); LLPanelAvatar* getPanelAvatar() const { return mPanelAvatar; } - void setDataRequested(bool requested) { mDataRequested = requested; } bool isDataRequested() const { return mDataRequested; } @@ -137,30 +136,33 @@ class LLPanelAvatarSecondLife // WARNING! The order of the inheritance here matters!! Do not change. - KLW class LLPanelAvatarWeb : public LLPanelAvatarTab - , public LLWebBrowserCtrlObserver + , public LLViewerMediaObserver { public: LLPanelAvatarWeb(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar); /*virtual*/ ~LLPanelAvatarWeb(); /*virtual*/ BOOL postBuild(void); + /*virtual*/ void refresh(); + /*virtual*/ void onVisibilityChange(BOOL new_visibility); void enableControls(BOOL own_avatar); void setWebURL(std::string url); void load(std::string url); + static void onURLKeystroke(LLLineEditor* editor, void* data); static void onCommitLoad(LLUICtrl* ctrl, void* data); static void onCommitURL(LLUICtrl* ctrl, void* data); static void onClickWebProfileHelp(void *); - // browser observer impls - virtual void onStatusTextChange( const EventType& eventIn ); - virtual void onLocationChange( const EventType& eventIn ); + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); private: std::string mHome; - LLWebBrowserCtrl* mWebBrowser; + std::string mNavigateTo; + LLMediaCtrl* mWebBrowser; }; diff --git a/linden/indra/newview/llpanelclassified.cpp b/linden/indra/newview/llpanelclassified.cpp index 224947922..99b6cf661 100644 --- a/linden/indra/newview/llpanelclassified.cpp +++ b/linden/indra/newview/llpanelclassified.cpp @@ -70,7 +70,7 @@ #include "llviewerwindow.h" // for window width, height #include "llappviewer.h" // abortQuit() -#include "hippoGridManager.h" +#include "hippogridmanager.h" // [RLVa:KB] #include "rlvhandler.h" @@ -146,7 +146,7 @@ class LLClassifiedTeleportHandler : public LLCommandHandler const bool from_search = true; LLPanelClassified::sendClassifiedClickMessage(classified_id, "teleport", from_search); // Invoke teleport - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = true; return LLURLDispatcher::dispatch(url, web, trusted_browser); } diff --git a/linden/indra/newview/llpaneldebug.cpp b/linden/indra/newview/llpaneldebug.cpp index c804fcea9..745daf597 100644 --- a/linden/indra/newview/llpaneldebug.cpp +++ b/linden/indra/newview/llpaneldebug.cpp @@ -42,7 +42,7 @@ #include "llfontgl.h" // project includes -#include "audioengine.h" +#include "llaudioengine.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcolorswatch.h" diff --git a/linden/indra/newview/llpaneldirfind.cpp b/linden/indra/newview/llpaneldirfind.cpp index 609f5cccd..719a7a06d 100644 --- a/linden/indra/newview/llpaneldirfind.cpp +++ b/linden/indra/newview/llpaneldirfind.cpp @@ -50,6 +50,7 @@ #include "llviewercontrol.h" #include "llmenucommands.h" #include "llmenugl.h" +#include "llpluginclassmedia.h" #include "lltextbox.h" #include "lluiconstants.h" #include "llviewerimagelist.h" @@ -61,6 +62,7 @@ #include "lluictrlfactory.h" #include "llfloaterdirectory.h" #include "llpaneldirbrowser.h" +#include "llpluginclassmedia.h" #include <boost/tokenizer.hpp> #if LL_WINDOWS @@ -72,7 +74,7 @@ #include "boost/lexical_cast.hpp" #endif -#include "hippoGridManager.h" +#include "hippogridmanager.h" //--------------------------------------------------------------------------- // LLPanelDirFindAll - Google search appliance based search @@ -143,9 +145,11 @@ BOOL LLPanelDirFind::postBuild() } - mWebBrowser = getChild<LLWebBrowserCtrl>(mBrowserName); + mWebBrowser = getChild<LLMediaCtrl>(mBrowserName); if (mWebBrowser) { + mWebBrowser->addObserver(this); + // new pages appear in same window as the results page now mWebBrowser->setOpenInInternalBrowser( false ); mWebBrowser->setOpenInExternalBrowser( false ); @@ -156,9 +160,6 @@ BOOL LLPanelDirFind::postBuild() // redirect 404 pages from S3 somewhere else mWebBrowser->set404RedirectUrl( getString("redirect_404_url") ); - // Track updates for progress display. - mWebBrowser->addObserver(this); - navigateToDefaultPage(); } @@ -167,8 +168,6 @@ BOOL LLPanelDirFind::postBuild() LLPanelDirFind::~LLPanelDirFind() { - if (mWebBrowser) - mWebBrowser->remObserver(this); } // virtual @@ -198,10 +197,17 @@ void LLPanelDirFind::draw() // virtual void LLPanelDirFind::onVisibilityChange(BOOL new_visibility) { + LLPluginClassMedia::EPriority new_priority; if (new_visibility) { mFloaterDirectory->hideAllDetailPanels(); + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; } + else + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + + mWebBrowser->getMediaPlugin()->setPriority(new_priority); + LLPanel::onVisibilityChange(new_visibility); } @@ -485,19 +491,27 @@ void LLPanelDirFind::onClickSearch(void* data) LLFloaterDirectory::sNewSearchCount++; } -void LLPanelDirFind::onNavigateBegin( const EventType& eventIn ) +void LLPanelDirFind::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) { - childSetText("status_text", getString("loading_text")); -} - -void LLPanelDirFind::onNavigateComplete( const EventType& eventIn ) -{ - childSetText("status_text", getString("done_text")); -} - -void LLPanelDirFind::onLocationChange( const EventType& eventIn ) -{ - llinfos << eventIn.getStringValue() << llendl; + switch(event) + { + case MEDIA_EVENT_NAVIGATE_BEGIN: + childSetText("status_text", getString("loading_text")); + break; + + case MEDIA_EVENT_NAVIGATE_COMPLETE: + childSetText("status_text", getString("done_text")); + break; + + case MEDIA_EVENT_LOCATION_CHANGED: + // Debugging info to console + llinfos << self->getLocation() << llendl; + break; + + default: + // Having a default case makes the compiler happy. + break; + } } //--------------------------------------------------------------------------- diff --git a/linden/indra/newview/llpaneldirfind.h b/linden/indra/newview/llpaneldirfind.h index 1a97f4b58..d3dda6e7b 100644 --- a/linden/indra/newview/llpaneldirfind.h +++ b/linden/indra/newview/llpaneldirfind.h @@ -34,19 +34,18 @@ #define LL_LLPANELDIRFIND_H #include "llpaneldirbrowser.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" class LLUICtrl; class LLLineEditor; class LLPanelDirFindAll; class LLFloaterDirectory; -class LLWebBrowserCtrlObserver; // This class in an abstract base class for all new style search widgets. It contains a pointer to a web browser control // class LLPanelDirFind : public LLPanelDirBrowser, - public LLWebBrowserCtrlObserver + public LLViewerMediaObserver { public: LLPanelDirFind(const std::string& name, LLFloaterDirectory* floater, const std::string& browser_name); @@ -73,15 +72,11 @@ class LLPanelDirFind static void onCommitSearch(LLUICtrl*, void* data); static void onClickHelp( void* data ); - /*virtual*/ void onNavigateBegin( const EventType& eventIn ); - /*virtual*/ void onNavigateComplete( const EventType& eventIn ); - - // Used to update progress indicator - /*virtual*/ void onLocationChange( const EventType& eventIn ); - // Debugging info to console + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); protected: - LLWebBrowserCtrl* mWebBrowser; + LLMediaCtrl* mWebBrowser; std::string mBrowserName; }; diff --git a/linden/indra/newview/llpaneldirgroups.cpp b/linden/indra/newview/llpaneldirgroups.cpp index 1aa2e8625..411951466 100644 --- a/linden/indra/newview/llpaneldirgroups.cpp +++ b/linden/indra/newview/llpaneldirgroups.cpp @@ -41,6 +41,7 @@ #include "llqueryflags.h" #include "llviewercontrol.h" #include "llviewerwindow.h" +#include "llmediactrl.h" LLPanelDirGroups::LLPanelDirGroups(const std::string& name, LLFloaterDirectory* floater) : LLPanelDirBrowser(name, floater) diff --git a/linden/indra/newview/llpaneldirland.cpp b/linden/indra/newview/llpaneldirland.cpp index c7029314f..3fdf37e7d 100644 --- a/linden/indra/newview/llpaneldirland.cpp +++ b/linden/indra/newview/llpaneldirland.cpp @@ -52,7 +52,7 @@ #include "llviewercontrol.h" #include "llviewermessage.h" #include "llnotify.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" //----------------------------------------------------------------------------- // Constants diff --git a/linden/indra/newview/llpaneldisplay.cpp b/linden/indra/newview/llpaneldisplay.cpp index 15b461578..a5c0d97a3 100644 --- a/linden/indra/newview/llpaneldisplay.cpp +++ b/linden/indra/newview/llpaneldisplay.cpp @@ -267,9 +267,6 @@ BOOL LLPanelDisplay::postBuild() // Object detail slider mCtrlDrawDistance = getChild<LLSliderCtrl>("DrawDistance"); - mDrawDistanceMeterText1 = getChild<LLTextBox>("DrawDistanceMeterText1"); - mDrawDistanceMeterText2 = getChild<LLTextBox>("DrawDistanceMeterText2"); - mCtrlDrawDistance->setCommitCallback(&LLPanelDisplay::updateMeterText); mCtrlDrawDistance->setCallbackUserData(this); // Object detail slider @@ -636,8 +633,6 @@ void LLPanelDisplay::setHiddenGraphicsState(bool isHidden) llassert(mAvatarText != NULL); llassert(mLightingText != NULL); llassert(mTerrainText != NULL); - llassert(mDrawDistanceMeterText1 != NULL); - llassert(mDrawDistanceMeterText2 != NULL); llassert(mAvatarCountText != NULL); // enable/disable the states @@ -684,16 +679,8 @@ void LLPanelDisplay::setHiddenGraphicsState(bool isHidden) mAvatarText->setVisible(!isHidden); mLightingText->setVisible(!isHidden); mTerrainText->setVisible(!isHidden); - mDrawDistanceMeterText1->setVisible(!isHidden); - mDrawDistanceMeterText2->setVisible(!isHidden); mAvatarCountText->setVisible(!isHidden); - // hide one meter text if we're making things visible - if(!isHidden) - { - updateMeterText(mCtrlDrawDistance, this); - } - mMeshDetailText->setVisible(!isHidden); mCtrlAvatarMaxVisible->setVisible(!isHidden); @@ -998,22 +985,6 @@ void LLPanelDisplay::updateSliderText(LLUICtrl* ctrl, void* user_data) } } -void LLPanelDisplay::updateMeterText(LLUICtrl* ctrl, void* user_data) -{ - // get our UI widgets - LLPanelDisplay* panel = (LLPanelDisplay*)user_data; - LLSliderCtrl* slider = (LLSliderCtrl*) ctrl; - - LLTextBox* m1 = panel->getChild<LLTextBox>("DrawDistanceMeterText1"); - LLTextBox* m2 = panel->getChild<LLTextBox>("DrawDistanceMeterText2"); - - // toggle the two text boxes based on whether we have 1 or two digits - F32 val = slider->getValueF32(); - bool two_digits = val < 100; - m1->setVisible(two_digits); - m2->setVisible(!two_digits); -} - // static void LLPanelDisplay::onImpostorsEnable(LLUICtrl* ctrl, void* user_data) { diff --git a/linden/indra/newview/llpaneldisplay.h b/linden/indra/newview/llpaneldisplay.h index e92cd2fca..d7727e7fc 100644 --- a/linden/indra/newview/llpaneldisplay.h +++ b/linden/indra/newview/llpaneldisplay.h @@ -128,8 +128,6 @@ class LLPanelDisplay LLTextBox *mAvatarText; LLTextBox *mTerrainText; LLTextBox *mLightingText; - LLTextBox *mDrawDistanceMeterText1; - LLTextBox *mDrawDistanceMeterText2; LLTextBox *mMeshDetailText; LLTextBox *mLODFactorText; @@ -194,7 +192,6 @@ class LLPanelDisplay static void onCommitWindowedMode(LLUICtrl* ctrl, void *data); static void onApplyResolution(LLUICtrl* ctrl, void* data); static void updateSliderText(LLUICtrl* ctrl, void* user_data); - static void updateMeterText(LLUICtrl* ctrl, void* user_data); static void onImpostorsEnable(LLUICtrl* ctrl, void* user_data); /// callback for defaults diff --git a/linden/indra/newview/llpanelface.cpp b/linden/indra/newview/llpanelface.cpp index 68e603e83..b9a40da53 100644 --- a/linden/indra/newview/llpanelface.cpp +++ b/linden/indra/newview/llpanelface.cpp @@ -66,6 +66,7 @@ #include "llviewerstats.h" #include "llviewerwindow.h" #include "lluictrlfactory.h" +#include "llpluginclassmedia.h" // // Methods @@ -77,7 +78,6 @@ BOOL LLPanelFace::postBuild() LLTextureCtrl* mTextureCtrl; LLColorSwatchCtrl* mColorSwatch; - LLTextBox* mLabelTexGen; LLComboBox* mComboTexGen; LLCheckBoxCtrl *mCheckFullbright; @@ -85,7 +85,6 @@ BOOL LLPanelFace::postBuild() LLTextBox* mLabelColorTransp; LLSpinCtrl* mCtrlColorTransp; // transparency = 1 - alpha - LLTextBox* mLabelGlow; LLSpinCtrl* mCtrlGlow; setMouseOpaque(FALSE); @@ -156,7 +155,7 @@ BOOL LLPanelFace::postBuild() mCheckFullbright->setCommitCallback(LLPanelFace::onCommitFullbright); mCheckFullbright->setCallbackUserData( this ); } - mLabelTexGen = getChild<LLTextBox>("tex gen"); + mComboTexGen = getChild<LLComboBox>("combobox texgen"); if(mComboTexGen) { @@ -165,7 +164,6 @@ BOOL LLPanelFace::postBuild() mComboTexGen->setCallbackUserData( this ); } - mLabelGlow = getChild<LLTextBox>("glow label"); mCtrlGlow = getChild<LLSpinCtrl>("glow"); if(mCtrlGlow) { @@ -507,11 +505,6 @@ void LLPanelFace::getState() childSetEnabled("button align",FALSE); //mBtnAutoFix->setEnabled ( FALSE ); - if(LLViewerMedia::hasMedia()) - { - childSetEnabled("textbox autofix",editable); - childSetEnabled("button align",editable); - } //if ( LLMediaEngine::getInstance()->getMediaRenderer () ) // if ( LLMediaEngine::getInstance()->getMediaRenderer ()->isLoaded () ) // { @@ -568,7 +561,15 @@ void LLPanelFace::getState() } } } + + if(LLViewerMedia::textureHasMedia(id)) + { + childSetEnabled("textbox autofix",editable); + childSetEnabled("button align",editable); + } + } + LLAggregatePermissions texture_perms; if(texture_ctrl) @@ -1117,14 +1118,18 @@ struct LLPanelFaceSetMediaFunctor : public LLSelectedTEFunctor { virtual bool apply(LLViewerObject* object, S32 te) { + // TODO: the media impl pointer should actually be stored by the texture + viewer_media_t pMediaImpl = LLViewerMedia::getMediaImplFromTextureID(object->getTE ( te )->getID()); // only do this if it's a media texture - if ( object->getTE ( te )->getID() == LLViewerMedia::getMediaTextureID() ) + if ( pMediaImpl.notNull()) { - S32 media_width, media_height; - S32 texture_width, texture_height; - if ( LLViewerMedia::getMediaSize( &media_width, &media_height ) - && LLViewerMedia::getTextureSize( &texture_width, &texture_height ) ) + LLPluginClassMedia *media = pMediaImpl->getMediaPlugin(); + if(media) { + S32 media_width = media->getWidth(); + S32 media_height = media->getHeight(); + S32 texture_width = media->getTextureWidth(); + S32 texture_height = media->getTextureHeight(); F32 scale_s = (F32)media_width / (F32)texture_width; F32 scale_t = (F32)media_height / (F32)texture_height; diff --git a/linden/indra/newview/llpanelgroupgeneral.cpp b/linden/indra/newview/llpanelgroupgeneral.cpp index e0d637671..7ff25a7b9 100644 --- a/linden/indra/newview/llpanelgroupgeneral.cpp +++ b/linden/indra/newview/llpanelgroupgeneral.cpp @@ -34,7 +34,7 @@ #include "llpanelgroupgeneral.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include "lluictrlfactory.h" #include "llagent.h" @@ -561,9 +561,13 @@ bool LLPanelGroupGeneral::apply(std::string& mesg) gIMMgr->saveIgnoreGroup(); } - mCtrlReceiveNotices->resetDirty(); //resetDirty() here instead of in update because this is where the settings - mCtrlListGroup->resetDirty(); //are actually being applied. onCommitUserOnly doesn't call updateChanged directly. - mCtrlReceiveChat->resetDirty(); + // Make sure we update the group list in our contacts list and our IMs -- MC + if (gIMMgr) + { + // update the talk view + gIMMgr->refresh(); + } + gAgent.fireEvent(new LLEvent(&gAgent, "new group"), ""); mChanged = FALSE; @@ -778,21 +782,14 @@ void LLPanelGroupGeneral::update(LLGroupChange gc) { mCtrlReceiveNotices->setEnabled(mAllowEdit); } + mCtrlReceiveNotices->resetDirty(); } if (mCtrlReceiveChat) { mCtrlReceiveChat->setVisible(is_member); mCtrlReceiveChat->setEnabled(TRUE); - } - - if (mCtrlListGroup) - { - mCtrlListGroup->setVisible(is_member); - if (is_member) - { - mCtrlListGroup->setEnabled(mAllowEdit); - } + mCtrlReceiveChat->resetDirty(); } diff --git a/linden/indra/newview/llpanelgrouplandmoney.cpp b/linden/indra/newview/llpanelgrouplandmoney.cpp index bded59c30..3f128fe28 100644 --- a/linden/indra/newview/llpanelgrouplandmoney.cpp +++ b/linden/indra/newview/llpanelgrouplandmoney.cpp @@ -55,7 +55,7 @@ #include "llfloaterworldmap.h" #include "llviewermessage.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" //////////////////////////////////////////////////////////////////////////// diff --git a/linden/indra/newview/llpanelinventory.cpp b/linden/indra/newview/llpanelinventory.cpp index 41ba5130e..277ab150e 100644 --- a/linden/indra/newview/llpanelinventory.cpp +++ b/linden/indra/newview/llpanelinventory.cpp @@ -82,7 +82,7 @@ #include "llviewerwindow.h" #include "llwearable.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // [RLVa:KB] #include "rlvhandler.h" @@ -145,7 +145,7 @@ class LLTaskInvFVBridge : public LLFolderViewEventListener virtual void move(LLFolderViewEventListener* parent_listener); virtual BOOL isItemCopyable() const; virtual BOOL copyToClipboard() const; - virtual void cutToClipboard(); + virtual BOOL cutToClipboard() const; virtual BOOL isClipboardPasteable() const; virtual void pasteFromClipboard(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); @@ -594,8 +594,9 @@ BOOL LLTaskInvFVBridge::copyToClipboard() const return FALSE; } -void LLTaskInvFVBridge::cutToClipboard() +BOOL LLTaskInvFVBridge::cutToClipboard() const { + return FALSE; } BOOL LLTaskInvFVBridge::isClipboardPasteable() const diff --git a/linden/indra/newview/llpanelland.cpp b/linden/indra/newview/llpanelland.cpp index ea6a55795..d1eee80b3 100644 --- a/linden/indra/newview/llpanelland.cpp +++ b/linden/indra/newview/llpanelland.cpp @@ -49,7 +49,7 @@ #include "lluictrlfactory.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // [RLVa:KB] #include "rlvhandler.h" diff --git a/linden/indra/newview/llpanellandaudio.cpp b/linden/indra/newview/llpanellandaudio.cpp new file mode 100644 index 000000000..0247009bb --- /dev/null +++ b/linden/indra/newview/llpanellandaudio.cpp @@ -0,0 +1,195 @@ +/** + * @file llpanellandaudio.cpp + * @brief Allows configuration of "media" for a land parcel, + * for example movies, web pages, and audio. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanellandaudio.h" + +// viewer includes +#include "llmimetypes.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "lluictrlfactory.h" + +// library includes +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llfloaterurlentry.h" +#include "llfocusmgr.h" +#include "lllineeditor.h" +#include "llparcel.h" +#include "lltextbox.h" +#include "llradiogroup.h" +#include "llspinctrl.h" +#include "llsdutil.h" +#include "lltexturectrl.h" +#include "roles_constants.h" +#include "llscrolllistctrl.h" + +// Values for the parcel voice settings radio group +enum +{ + kRadioVoiceChatEstate = 0, + kRadioVoiceChatPrivate = 1, + kRadioVoiceChatDisable = 2 +}; + +//--------------------------------------------------------------------------- +// LLPanelLandAudio +//--------------------------------------------------------------------------- + +LLPanelLandAudio::LLPanelLandAudio(LLParcelSelectionHandle& parcel) +: LLPanel(std::string("land_media_panel")), mParcel(parcel) +{ +} + + +// virtual +LLPanelLandAudio::~LLPanelLandAudio() +{ +} + + +BOOL LLPanelLandAudio::postBuild() +{ + mCheckSoundLocal = getChild<LLCheckBoxCtrl>("check_sound_local"); + childSetCommitCallback("check_sound_local", onCommitAny, this); + + mRadioVoiceChat = getChild<LLRadioGroup>("parcel_voice_channel"); + childSetCommitCallback("parcel_voice_channel", onCommitAny, this); + + mMusicURLEdit = getChild<LLLineEditor>("music_url"); + childSetCommitCallback("music_url", onCommitAny, this); + + mMusicUrlCheck = getChild<LLCheckBoxCtrl>("hide_music_url"); + childSetCommitCallback("hide_music_url", onCommitAny, this); + + return TRUE; +} + + +// public +void LLPanelLandAudio::refresh() +{ + LLParcel *parcel = mParcel->getParcel(); + + if (!parcel) + { + clearCtrls(); + } + else + { + // something selected, hooray! + + // Display options + BOOL can_change_media = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_MEDIA); + + mMusicURLEdit->setText(parcel->getMusicURL()); + mMusicURLEdit->setEnabled( can_change_media ); + + mMusicUrlCheck->set( parcel->getObscureMusic() ); + mMusicUrlCheck->setEnabled( can_change_media ); + + mCheckSoundLocal->set( parcel->getSoundLocal() ); + mCheckSoundLocal->setEnabled( can_change_media ); + + if(parcel->getParcelFlagAllowVoice()) + { + if(parcel->getParcelFlagUseEstateVoiceChannel()) + mRadioVoiceChat->setSelectedIndex(kRadioVoiceChatEstate); + else + mRadioVoiceChat->setSelectedIndex(kRadioVoiceChatPrivate); + } + else + { + mRadioVoiceChat->setSelectedIndex(kRadioVoiceChatDisable); + } + + LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); + mRadioVoiceChat->setEnabled( region && region->isVoiceEnabled() && can_change_media ); + } +} +// static +void LLPanelLandAudio::onCommitAny(LLUICtrl*, void *userdata) +{ + LLPanelLandAudio *self = (LLPanelLandAudio *)userdata; + + LLParcel* parcel = self->mParcel->getParcel(); + if (!parcel) + { + return; + } + + // Extract data from UI + BOOL sound_local = self->mCheckSoundLocal->get(); + int voice_setting = self->mRadioVoiceChat->getSelectedIndex(); + std::string music_url = self->mMusicURLEdit->getText(); + U8 obscure_music = self->mMusicUrlCheck->get(); + + + BOOL voice_enabled; + BOOL voice_estate_chan; + + switch(voice_setting) + { + default: + case kRadioVoiceChatEstate: + voice_enabled = TRUE; + voice_estate_chan = TRUE; + break; + case kRadioVoiceChatPrivate: + voice_enabled = TRUE; + voice_estate_chan = FALSE; + break; + case kRadioVoiceChatDisable: + voice_enabled = FALSE; + voice_estate_chan = FALSE; + break; + } + + // Remove leading/trailing whitespace (common when copying/pasting) + LLStringUtil::trim(music_url); + + // Push data into current parcel + parcel->setParcelFlag(PF_ALLOW_VOICE_CHAT, voice_enabled); + parcel->setParcelFlag(PF_USE_ESTATE_VOICE_CHAN, voice_estate_chan); + parcel->setParcelFlag(PF_SOUND_LOCAL, sound_local); + parcel->setMusicURL(music_url); + parcel->setObscureMusic(obscure_music); + + // Send current parcel data upstream to server + LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); + + // Might have changed properties, so let's redraw! + self->refresh(); +} diff --git a/linden/indra/llmedia/llmediaimplexample2.h b/linden/indra/newview/llpanellandaudio.h similarity index 54% rename from linden/indra/llmedia/llmediaimplexample2.h rename to linden/indra/newview/llpanellandaudio.h index 6a4f80b3d..3d5d63347 100644 --- a/linden/indra/llmedia/llmediaimplexample2.h +++ b/linden/indra/newview/llpanellandaudio.h @@ -1,6 +1,7 @@ /** - * @file llmediaimplexample2.h - * @brief Example 2 of a media impl concrete class + * @file llpanellandaudio.h + * @brief Allows configuration of "audio" for a land parcel. + * * * $LicenseInfo:firstyear=2007&license=viewergpl$ * @@ -30,47 +31,33 @@ * $/LicenseInfo$ */ -#ifndef LLMEDIAIMPLEXAMPLE2_H -#define LLMEDIAIMPLEXAMPLE2_H +#ifndef LLPANELLANDAUDIO_H +#define LLPANELLANDAUDIO_H -#include "llmediaimplcommon.h" -#include "llmediaimplfactory.h" +#include "lllineeditor.h" +#include "llpanel.h" +#include "llparcelselection.h" +#include "lluifwd.h" // widget pointer types -class LLMediaManagerData; -class LLMediaImplMaker; - -class LLMediaImplExample2 : - public LLMediaImplCommon -{ - public: - LLMediaImplExample2(); - - static bool startup( LLMediaManagerData* init_data ); - static bool closedown(); - - /* virtual */ bool init(); - /* virtual */ bool navigateTo( const std::string url ); - /* virtual */ bool load( const std::string url ); - /* virtual */ std::string getVersion(); - /* virtual */ bool updateMedia(); - /* virtual */ unsigned char* getMediaData(); - /* virtual */ bool reset(); - /* virtual */ bool setRequestedMediaSize( int width, int height ); - - private: - unsigned char* mMediaPixels; - int mXpos; - int mYpos; -}; - -class LLMediaImplExample2Maker : public LLMediaImplMaker +class LLPanelLandAudio + : public LLPanel { - public: - LLMediaImplExample2Maker(); - LLMediaImplExample2* create() - { - return new LLMediaImplExample2(); - } +public: + LLPanelLandAudio(LLSafeHandle<LLParcelSelection>& parcelp); + /*virtual*/ ~LLPanelLandAudio(); + /*virtual*/ BOOL postBuild(); + void refresh(); + +private: + static void onCommitAny(LLUICtrl* ctrl, void *userdata); + +private: + LLCheckBoxCtrl* mCheckSoundLocal; + LLRadioGroup* mRadioVoiceChat; + LLLineEditor* mMusicURLEdit; + LLCheckBoxCtrl* mMusicUrlCheck; + + LLSafeHandle<LLParcelSelection>& mParcel; }; -#endif // LLMEDIAIMPLEXAMPLE2_H +#endif diff --git a/linden/indra/newview/llpanellandmedia.cpp b/linden/indra/newview/llpanellandmedia.cpp index bebd69e4e..b7df164ca 100644 --- a/linden/indra/newview/llpanellandmedia.cpp +++ b/linden/indra/newview/llpanellandmedia.cpp @@ -55,7 +55,7 @@ #include "lltexturectrl.h" #include "roles_constants.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" //--------------------------------------------------------------------------- // LLPanelLandMedia @@ -358,13 +358,21 @@ void LLPanelLandMedia::setMediaType(const std::string& mime_type) std::string media_key = LLMIMETypes::widgetType(mime_type); mMediaTypeCombo->setValue(media_key); + childSetText("mime_type", mime_type); } void LLPanelLandMedia::setMediaURL(const std::string& media_url) { mMediaURLEdit->setText(media_url); + LLParcel *parcel = mParcel->getParcel(); + if(parcel) + parcel->setMediaCurrentURL(media_url); + // LLViewerMedia::navigateHome(); + mMediaURLEdit->onCommit(); +// // LLViewerParcelMedia::sendMediaNavigateMessage(media_url); +// childSetText("current_url", media_url); } std::string LLPanelLandMedia::getMediaURL() @@ -452,4 +460,4 @@ void LLPanelLandMedia::onSetBtn(void *userdata) { parent_floater->addDependentFloater(self->mURLEntryFloater.get()); } -} +} \ No newline at end of file diff --git a/linden/indra/newview/llpanellandmedia.h b/linden/indra/newview/llpanellandmedia.h index 6a53dd42a..845b95340 100644 --- a/linden/indra/newview/llpanellandmedia.h +++ b/linden/indra/newview/llpanellandmedia.h @@ -82,4 +82,4 @@ class LLPanelLandMedia LLSafeHandle<LLParcelSelection>& mParcel; }; -#endif +#endif \ No newline at end of file diff --git a/linden/indra/newview/llpanellogin.cpp b/linden/indra/newview/llpanellogin.cpp index 69539c7c7..6464f0bb8 100644 --- a/linden/indra/newview/llpanellogin.cpp +++ b/linden/indra/newview/llpanellogin.cpp @@ -36,8 +36,8 @@ #include "llpanelgeneral.h" -#include "hippoGridManager.h" -#include "hippoLimits.h" +#include "hippogridmanager.h" +#include "hippolimits.h" #include "floatergridmanager.h" #include "indra_constants.h" // for key and mask constants @@ -73,12 +73,10 @@ #include "lluictrlfactory.h" #include "llhttpclient.h" #include "llweb.h" -#include "llwebbrowserctrl.h" #include "viewerversion.h" +#include "llmediactrl.h" -#include "llfloaterhtml.h" - -#include "llfloaterhtmlhelp.h" +#include "llfloatermediabrowser.h" #include "llfloatertos.h" #include "llglheaders.h" @@ -101,7 +99,7 @@ class LLLoginRefreshHandler : public LLCommandHandler public: // don't allow from external browsers LLLoginRefreshHandler() : LLCommandHandler("login_refresh", true) { } - bool handle(const LLSD& tokens, const LLSD& query_map, LLWebBrowserCtrl* web) + bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) { if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) { @@ -291,16 +289,15 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, #endif // get the web browser control - LLWebBrowserCtrl* web_browser = getChild<LLWebBrowserCtrl>("login_html"); + LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html"); + web_browser->addObserver(this); + // Need to handle login secondlife:///app/ URLs web_browser->setTrusted( true ); - // observe browser events - web_browser->addObserver( this ); - // don't make it a tab stop until SL-27594 is fixed web_browser->setTabStop(FALSE); - web_browser->navigateToLocalPage( "loading", "loading.html" ); + // web_browser->navigateToLocalPage( "loading", "loading.html" ); // make links open in external browser web_browser->setOpenInExternalBrowser( true ); @@ -335,7 +332,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, void LLPanelLogin::setSiteIsAlive( bool alive ) { - LLWebBrowserCtrl* web_browser = getChild<LLWebBrowserCtrl>("login_html"); + LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html"); // if the contents of the site was retrieved if ( alive ) { @@ -398,6 +395,11 @@ LLPanelLogin::~LLPanelLogin() //// We know we're done with the image, so be rid of it. //gImageList.deleteImage( mLogoImage ); + + if ( gFocusMgr.getDefaultKeyboardFocus() == this ) + { + gFocusMgr.setDefaultKeyboardFocus(NULL); + } } // virtual @@ -779,7 +781,7 @@ void LLPanelLogin::setAlwaysRefresh(bool refresh) { if (LLStartUp::getStartupState() >= STATE_LOGIN_CLEANUP) return; - LLWebBrowserCtrl* web_browser = sInstance->getChild<LLWebBrowserCtrl>("login_html"); + LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); if (web_browser) { @@ -952,25 +954,28 @@ void LLPanelLogin::loadLoginPage() #endif #endif - LLWebBrowserCtrl* web_browser = sInstance->getChild<LLWebBrowserCtrl>("login_html"); + LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); // navigate to the "real" page - web_browser->navigateTo( oStr.str() ); + web_browser->navigateTo( oStr.str(), "text/html" ); } -void LLPanelLogin::onNavigateComplete( const EventType& eventIn ) +void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event) { - LLWebBrowserCtrl* web_browser = sInstance->getChild<LLWebBrowserCtrl>("login_html"); - if (web_browser) + if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) { - // *HACK HACK HACK HACK! - /* Stuff a Tab key into the browser now so that the first field will - ** get the focus! The embedded javascript on the page that properly - ** sets the initial focus in a real web browser is not working inside - ** the viewer, so this is an UGLY HACK WORKAROUND for now. - */ - // Commented out as it's not reliable - //web_browser->handleKey(KEY_TAB, MASK_NONE, false); + LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); + if (web_browser) + { + // *HACK HACK HACK HACK! + /* Stuff a Tab key into the browser now so that the first field will + ** get the focus! The embedded javascript on the page that properly + ** sets the initial focus in a real web browser is not working inside + ** the viewer, so this is an UGLY HACK WORKAROUND for now. + */ + // Commented out as it's not reliable + //web_browser->handleKey(KEY_TAB, MASK_NONE, false); + } } } diff --git a/linden/indra/newview/llpanellogin.h b/linden/indra/newview/llpanellogin.h index 15c2d2804..c99fa3064 100644 --- a/linden/indra/newview/llpanellogin.h +++ b/linden/indra/newview/llpanellogin.h @@ -35,14 +35,14 @@ #include "llpanel.h" #include "llmemory.h" // LLPointer<> -#include "llwebbrowserctrl.h" // LLWebBrowserCtrlObserver +#include "llmediactrl.h" // LLMediaCtrlObserver class LLUIImage; class LLPanelLogin: public LLPanel, - public LLWebBrowserCtrlObserver + public LLViewerMediaObserver { LOG_CLASS(LLPanelLogin); public: @@ -84,6 +84,9 @@ class LLPanelLogin: static void setAlwaysRefresh(bool refresh); static void mungePassword(LLUICtrl* caller, void* user_data); + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + private: static void onClickConnect(void*); static void onClickGrid(void*); @@ -91,7 +94,6 @@ class LLPanelLogin: static bool newAccountAlertCallback(const LLSD& notification, const LLSD& response); static void onClickQuit(void*); static void onClickVersion(void*); - virtual void onNavigateComplete( const EventType& eventIn ); static void onClickForgotPassword(void*); static void onPassKey(LLLineEditor* caller, void* user_data); static void onSelectServer(LLUICtrl*, void*); diff --git a/linden/indra/newview/llpanelmediahud.cpp b/linden/indra/newview/llpanelmediahud.cpp new file mode 100644 index 000000000..39c4b637b --- /dev/null +++ b/linden/indra/newview/llpanelmediahud.cpp @@ -0,0 +1,667 @@ +/** + * @file llpanelmsgs.cpp + * @brief Message popup preferences panel + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +//LLPanelMediaHUD +#include "llagent.h" +#include "llparcel.h" +#include "llpanel.h" +#include "llselectmgr.h" +#include "llrender.h" +#include "lldrawable.h" +#include "llviewerwindow.h" +#include "lluictrlfactory.h" +#include "llbutton.h" +#include "llface.h" +#include "llhudview.h" +#include "lliconctrl.h" +#include "lltoolpie.h" +#include "llviewercamera.h" +#include "llpanelmediahud.h" +#include "llpluginclassmedia.h" +#include "llviewercontrol.h" +#include "llviewerparcelmgr.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h" +#include "llvovolume.h" +#include "llweb.h" + +glh::matrix4f glh_get_current_modelview(); +glh::matrix4f glh_get_current_projection(); + +const F32 ZOOM_NEAR_PADDING = 1.0f; +const F32 ZOOM_MEDIUM_PADDING = 1.2f; +const F32 ZOOM_FAR_PADDING = 1.5f; + +// +// LLPanelMediaHUD +// + +LLPanelMediaHUD::LLPanelMediaHUD(viewer_media_t media_impl) + : mMediaImpl(media_impl) +{ + mMediaFocus = false; + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_hud.xml"); + mMouseMoveTimer.reset(); + mFadeTimer.stop(); + mCurrentZoom = ZOOM_NONE; + mScrollState = SCROLL_NONE; + + mPanelHandle.bind(this); +} +LLPanelMediaHUD::~LLPanelMediaHUD() +{ + mMediaImpl = NULL; +} + +BOOL LLPanelMediaHUD::postBuild() +{ + LLButton* close_btn = getChild<LLButton>("close"); + close_btn->setClickedCallback(onClickClose, this); + + LLButton* back_btn = getChild<LLButton>("back"); + back_btn->setClickedCallback(onClickBack, this); + + LLButton* fwd_btn = getChild<LLButton>("fwd"); + fwd_btn->setClickedCallback(onClickForward, this); + + LLButton* home_btn = getChild<LLButton>("home"); + home_btn->setClickedCallback(onClickHome, this); + + LLButton* stop_btn = getChild<LLButton>("stop"); + stop_btn->setClickedCallback(onClickStop, this); + + LLButton* media_stop_btn = getChild<LLButton>("media_stop"); + media_stop_btn->setClickedCallback(onClickStop, this); + + LLButton* reload_btn = getChild<LLButton>("reload"); + reload_btn->setClickedCallback(onClickReload, this); + + LLButton* play_btn = getChild<LLButton>("play"); + play_btn->setClickedCallback(onClickPlay, this); + + LLButton* pause_btn = getChild<LLButton>("pause"); + pause_btn->setClickedCallback(onClickPause, this); + + LLButton* open_btn = getChild<LLButton>("new_window"); + open_btn->setClickedCallback(onClickOpen, this); + + LLButton* zoom_btn = getChild<LLButton>("zoom_frame"); + zoom_btn->setClickedCallback(onClickZoom, this); + + LLButton* open_btn_h = getChild<LLButton>("new_window_hover"); + open_btn_h->setClickedCallback(onClickOpen, this); + + LLButton* zoom_btn_h = getChild<LLButton>("zoom_frame_hover"); + zoom_btn_h->setClickedCallback(onClickZoom, this); + + LLButton* scroll_up_btn = getChild<LLButton>("scrollup"); + scroll_up_btn->setClickedCallback(onScrollUp, this); + scroll_up_btn->setHeldDownCallback(onScrollUpHeld); + scroll_up_btn->setMouseUpCallback(onScrollStop); + LLButton* scroll_left_btn = getChild<LLButton>("scrollleft"); + scroll_left_btn->setClickedCallback(onScrollLeft, this); + scroll_left_btn->setHeldDownCallback(onScrollLeftHeld); + scroll_left_btn->setMouseUpCallback(onScrollStop); + LLButton* scroll_right_btn = getChild<LLButton>("scrollright"); + scroll_right_btn->setClickedCallback(onScrollRight, this); + scroll_right_btn->setHeldDownCallback(onScrollLeftHeld); + scroll_right_btn->setMouseUpCallback(onScrollStop); + LLButton* scroll_down_btn = getChild<LLButton>("scrolldown"); + scroll_down_btn->setClickedCallback(onScrollDown, this); + scroll_down_btn->setHeldDownCallback(onScrollDownHeld); + scroll_down_btn->setMouseUpCallback(onScrollStop); + + mMouseInactiveTime = gSavedSettings.getF32("MediaControlTimeout"); + mControlFadeTime = gSavedSettings.getF32("MediaControlFadeTime"); + + mCurrentZoom = ZOOM_NONE; + // clicks on HUD buttons do not remove keyboard focus from media + setIsChrome(TRUE); + return TRUE; +} + +void LLPanelMediaHUD::updateShape() +{ + const S32 MIN_HUD_WIDTH=200; + const S32 MIN_HUD_HEIGHT=120; + + LLPluginClassMedia* media_plugin = NULL; + if(mMediaImpl.notNull() && mMediaImpl->hasMedia()) + { + media_plugin = mMediaImpl->getMediaPlugin(); + } + + // Early out for no media plugin + if(media_plugin == NULL) + { + setVisible(FALSE); + return; + } + + LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + + bool can_navigate = parcel->getMediaAllowNavigate(); + + // LLObjectSelectionHandle selection = LLViewerMediaFocus::getInstance()->getSelection(); + + LLSelectNode* nodep = mMediaFocus ? LLSelectMgr::getInstance()->getSelection()->getFirstNode() : LLSelectMgr::getInstance()->getHoverNode(); + if(! nodep) + { + return; + } + setVisible(FALSE); + LLViewerObject* objectp = nodep->getObject(); + + if (objectp) + { + + // Set the state of the buttons + LLButton* back_btn = getChild<LLButton>("back"); + LLButton* fwd_btn = getChild<LLButton>("fwd"); + LLButton* reload_btn = getChild<LLButton>("reload"); + LLButton* play_btn = getChild<LLButton>("play"); + LLButton* pause_btn = getChild<LLButton>("pause"); + LLButton* stop_btn = getChild<LLButton>("stop"); + LLButton* media_stop_btn = getChild<LLButton>("media_stop"); + LLButton* home_btn = getChild<LLButton>("home"); + LLButton* close_btn = getChild<LLButton>("close"); + LLButton* open_btn = getChild<LLButton>("new_window"); + LLPanel* media_focused_panel = getChild<LLPanel>("media_focused_controls"); + LLPanel* media_hover_panel = getChild<LLPanel>("media_hover_controls"); + back_btn->setVisible(true); + fwd_btn->setVisible(true); + reload_btn->setVisible(true); + stop_btn->setVisible(false); + home_btn->setVisible(true); + close_btn->setVisible(true); + open_btn->setVisible(true); + + + if(mMediaFocus) + { + back_btn->setEnabled(mMediaImpl->canNavigateBack() && can_navigate); + fwd_btn->setEnabled(mMediaImpl->canNavigateForward() && can_navigate); + stop_btn->setEnabled(can_navigate); + home_btn->setEnabled(can_navigate); + LLPluginClassMediaOwner::EMediaStatus result = media_plugin->getStatus(); + + if(media_plugin->pluginSupportsMediaTime()) + { + reload_btn->setEnabled(FALSE); + reload_btn->setVisible(FALSE); + media_stop_btn->setVisible(TRUE); + home_btn->setVisible(FALSE); + back_btn->setEnabled(TRUE); + fwd_btn->setEnabled(TRUE); + switch(result) + { + case LLPluginClassMediaOwner::MEDIA_PLAYING: + play_btn->setEnabled(FALSE); + play_btn->setVisible(FALSE); + pause_btn->setEnabled(TRUE); + pause_btn->setVisible(TRUE); + media_stop_btn->setEnabled(TRUE); + break; + case LLPluginClassMediaOwner::MEDIA_PAUSED: + default: + pause_btn->setEnabled(FALSE); + pause_btn->setVisible(FALSE); + play_btn->setEnabled(TRUE); + play_btn->setVisible(TRUE); + media_stop_btn->setEnabled(FALSE); + break; + } + } + else + { + play_btn->setVisible(FALSE); + pause_btn->setVisible(FALSE); + media_stop_btn->setVisible(FALSE); + if(result == LLPluginClassMediaOwner::MEDIA_LOADING) + { + reload_btn->setEnabled(FALSE); + reload_btn->setVisible(FALSE); + stop_btn->setEnabled(TRUE); + stop_btn->setVisible(TRUE); + } + else + { + reload_btn->setEnabled(TRUE); + reload_btn->setVisible(TRUE); + stop_btn->setEnabled(FALSE); + stop_btn->setVisible(FALSE); + } + } + } + media_focused_panel->setVisible(mMediaFocus); + media_hover_panel->setVisible(!mMediaFocus); + + if(media_plugin == NULL) + // Handle Scrolling + switch (mScrollState) + { + case SCROLL_UP: + media_plugin->scrollEvent(0, -1, MASK_NONE); + break; + case SCROLL_DOWN: + media_plugin->scrollEvent(0, 1, MASK_NONE); + break; + case SCROLL_LEFT: + mMediaImpl->handleKeyHere(KEY_LEFT, MASK_NONE); + break; + case SCROLL_RIGHT: + mMediaImpl->handleKeyHere(KEY_RIGHT, MASK_NONE); + break; + case SCROLL_NONE: + default: + break; + } + LLBBox screen_bbox; + setVisible(TRUE); + glh::matrix4f mat = glh_get_current_projection()*glh_get_current_modelview(); + std::vector<LLVector3>::iterator vert_it; + std::vector<LLVector3>::iterator vert_end; + std::vector<LLVector3> vect_face; + + LLVolume* volume = objectp->getVolume(); + + if (volume) + { + const LLVolumeFace& vf = volume->getVolumeFace(nodep->getLastSelectedTE()); + + const LLVector3* ext = vf.mExtents; + + LLVector3 center = (ext[0]+ext[1])*0.5f; + LLVector3 size = (ext[1]-ext[0])*0.5f; + LLVector3 vert[] = + { + center + size.scaledVec(LLVector3(1,1,1)), + center + size.scaledVec(LLVector3(-1,1,1)), + center + size.scaledVec(LLVector3(1,-1,1)), + center + size.scaledVec(LLVector3(-1,-1,1)), + center + size.scaledVec(LLVector3(1,1,-1)), + center + size.scaledVec(LLVector3(-1,1,-1)), + center + size.scaledVec(LLVector3(1,-1,-1)), + center + size.scaledVec(LLVector3(-1,-1,-1)), + }; + + LLVOVolume* vo = (LLVOVolume*) objectp; + + for (U32 i = 0; i < 8; i++) + { + vect_face.push_back(vo->volumePositionToAgent(vert[i])); + } + } + vert_it = vect_face.begin(); + vert_end = vect_face.end(); + + LLVector3 min = LLVector3(1,1,1); + LLVector3 max = LLVector3(-1,-1,-1); + for(; vert_it != vert_end; ++vert_it) + { + // project silhouette vertices into screen space + glh::vec3f screen_vert = glh::vec3f(vert_it->mV); + mat.mult_matrix_vec(screen_vert); + + // add to screenspace bounding box + update_min_max(min, max, LLVector3(screen_vert.v)); + } + + LLCoordGL screen_min; + screen_min.mX = llround((F32)gViewerWindow->getWindowWidth() * (min.mV[VX] + 1.f) * 0.5f); + screen_min.mY = llround((F32)gViewerWindow->getWindowHeight() * (min.mV[VY] + 1.f) * 0.5f); + + LLCoordGL screen_max; + screen_max.mX = llround((F32)gViewerWindow->getWindowWidth() * (max.mV[VX] + 1.f) * 0.5f); + screen_max.mY = llround((F32)gViewerWindow->getWindowHeight() * (max.mV[VY] + 1.f) * 0.5f); + + // grow panel so that screenspace bounding box fits inside "media_region" element of HUD + LLRect media_hud_rect; + getParent()->screenRectToLocal(LLRect(screen_min.mX, screen_max.mY, screen_max.mX, screen_min.mY), &media_hud_rect); + LLView* media_region = getChild<LLView>("media_region"); + media_hud_rect.mLeft -= media_region->getRect().mLeft; + media_hud_rect.mBottom -= media_region->getRect().mBottom; + media_hud_rect.mTop += getRect().getHeight() - media_region->getRect().mTop; + media_hud_rect.mRight += getRect().getWidth() - media_region->getRect().mRight; + + + LLRect old_hud_rect = media_hud_rect; + // keep all parts of HUD on-screen + media_hud_rect.intersectWith(getParent()->getLocalRect()); + + // If we had to clip the rect, don't display the border + childSetVisible("bg_image", false); + + // clamp to minimum size, keeping centered + media_hud_rect.setCenterAndSize(media_hud_rect.getCenterX(), media_hud_rect.getCenterY(), + llmax(MIN_HUD_WIDTH, media_hud_rect.getWidth()), llmax(MIN_HUD_HEIGHT, media_hud_rect.getHeight())); + + userSetShape(media_hud_rect); + + // Test mouse position to see if the cursor is stationary + LLCoordWindow cursor_pos_window; + getWindow()->getCursorPosition(&cursor_pos_window); + + // If last pos is not equal to current pos, the mouse has moved + // We need to reset the timer, and make sure the panel is visible + if(cursor_pos_window.mX != mLastCursorPos.mX || + cursor_pos_window.mY != mLastCursorPos.mY || + mScrollState != SCROLL_NONE) + { + mMouseMoveTimer.start(); + mLastCursorPos = cursor_pos_window; + } + + // Mouse has been stationary, but not for long enough to fade the UI + if(mMouseMoveTimer.getElapsedTimeF32() < mMouseInactiveTime) + { + // If we have started fading, reset the alpha values + if(mFadeTimer.getStarted()) + { + F32 alpha = 1.0f; + setAlpha(alpha); + mFadeTimer.stop(); + } + } + // If we need to start fading the UI (and we have not already started) + else if(! mFadeTimer.getStarted()) + { + mFadeTimer.reset(); + mFadeTimer.start(); + } + } +} +/*virtual*/ +void LLPanelMediaHUD::draw() +{ + if(mFadeTimer.getStarted()) + { + if(mFadeTimer.getElapsedTimeF32() >= mControlFadeTime) + { + setVisible(FALSE); + } + else + { + F32 time = mFadeTimer.getElapsedTimeF32(); + F32 alpha = llmax(lerp(1.0, 0.0, time / mControlFadeTime), 0.0f); + setAlpha(alpha); + } + } + LLPanel::draw(); +} +void LLPanelMediaHUD::setAlpha(F32 alpha) +{ + LLViewQuery query; + + LLView* query_view = mMediaFocus ? getChildView("media_focused_controls") : getChildView("media_hover_controls"); + child_list_t children = query(query_view); + for (child_list_iter_t child_iter = children.begin(); + child_iter != children.end(); ++child_iter) + { + LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(*child_iter); + if (ctrl) + ctrl->setAlpha(alpha); + } + + LLPanel::setAlpha(alpha); +} +BOOL LLPanelMediaHUD::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks); +} +bool LLPanelMediaHUD::isMouseOver() +{ + if( ! getVisible() ) + { + return false; + } + LLRect screen_rect; + LLCoordWindow cursor_pos_window; + getWindow()->getCursorPosition(&cursor_pos_window); + + localRectToScreen(getLocalRect(), &screen_rect); + // screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, &local_mouse_x, &local_mouse_y); + + if(screen_rect.pointInRect(cursor_pos_window.mX, cursor_pos_window.mY)) + { + return true; + } + return false; +} + +//static +void LLPanelMediaHUD::onClickClose(void* user_data) +{ + LLViewerMediaFocus::getInstance()->setFocusFace(FALSE, NULL, 0, NULL); + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if(this_panel->mCurrentZoom != ZOOM_NONE) + { + // gAgent.setFocusOnAvatar(TRUE, ANIMATE); + this_panel->mCurrentZoom = ZOOM_NONE; + } + this_panel->setVisible(FALSE); + +} + +//static +void LLPanelMediaHUD::onClickBack(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if (this_panel->mMediaImpl.notNull() && this_panel->mMediaImpl->hasMedia()) + { + if(this_panel->mMediaImpl->getMediaPlugin()->pluginSupportsMediaTime()) + { + this_panel->mMediaImpl->getMediaPlugin()->start(-2.0); + } + else + { + this_panel->mMediaImpl->getMediaPlugin()->browse_back(); + } + + } +} +//static +void LLPanelMediaHUD::onClickForward(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if (this_panel->mMediaImpl.notNull() && this_panel->mMediaImpl->hasMedia()) + { + if(this_panel->mMediaImpl->getMediaPlugin()->pluginSupportsMediaTime()) + { + this_panel->mMediaImpl->getMediaPlugin()->start(2.0); + } + else + { + this_panel->mMediaImpl->getMediaPlugin()->browse_forward(); + } + } +} +//static +void LLPanelMediaHUD::onClickHome(void* user_data) +{ + //LLViewerMedia::navigateHome(); + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if(this_panel->mMediaImpl.notNull()) + { + this_panel->mMediaImpl->navigateHome(); + } +} +//static +void LLPanelMediaHUD::onClickOpen(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if(this_panel->mMediaImpl.notNull()) + { + LLWeb::loadURL(this_panel->mMediaImpl->getMediaURL()); + } +} +//static +void LLPanelMediaHUD::onClickReload(void* user_data) +{ + //LLViewerMedia::navigateHome(); + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + if(objectp && this_panel->mMediaImpl.notNull()) + { + this_panel->mMediaImpl->navigateTo(objectp->getMediaURL()); + } +} +//static +void LLPanelMediaHUD::onClickPlay(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if (this_panel->mMediaImpl.notNull() && this_panel->mMediaImpl->hasMedia()) + { + this_panel->mMediaImpl->getMediaPlugin()->start(); + } +} +//static +void LLPanelMediaHUD::onClickPause(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if (this_panel->mMediaImpl.notNull() && this_panel->mMediaImpl->hasMedia()) + { + this_panel->mMediaImpl->getMediaPlugin()->pause(); + } +} +//static +void LLPanelMediaHUD::onClickStop(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if (this_panel->mMediaImpl.notNull() && this_panel->mMediaImpl->hasMedia()) + { + if(this_panel->mMediaImpl->getMediaPlugin()->pluginSupportsMediaTime()) + { + this_panel->mMediaImpl->getMediaPlugin()->stop(); + } + else + { + this_panel->mMediaImpl->getMediaPlugin()->browse_stop(); + } + } +} +//static +void LLPanelMediaHUD::onClickZoom(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + this_panel->nextZoomLevel(); +} +void LLPanelMediaHUD::nextZoomLevel() +{ + F32 zoom_padding = 0.0f; + S32 last_zoom_level = (S32)mCurrentZoom; + mCurrentZoom = (EZoomLevel)((last_zoom_level + 1) % (S32)ZOOM_END); + + switch (mCurrentZoom) + { + case ZOOM_NONE: + { + gAgent.setFocusOnAvatar(TRUE, ANIMATE); + break; + } + case ZOOM_MEDIUM: + { + zoom_padding = ZOOM_MEDIUM_PADDING; + break; + } + default: + { + gAgent.setFocusOnAvatar(TRUE, ANIMATE); + break; + } + } + + if (zoom_padding > 0.0f) + LLViewerMediaFocus::getInstance()->setCameraZoom(zoom_padding); +} +void LLPanelMediaHUD::onScrollUp(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if(this_panel->mMediaImpl.notNull() && this_panel->mMediaImpl->hasMedia()) + { + this_panel->mMediaImpl->getMediaPlugin()->scrollEvent(0, -1, MASK_NONE); + } +} +void LLPanelMediaHUD::onScrollUpHeld(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + this_panel->mScrollState = SCROLL_UP; +} +void LLPanelMediaHUD::onScrollRight(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if(this_panel->mMediaImpl.notNull()) + { + this_panel->mMediaImpl->handleKeyHere(KEY_RIGHT, MASK_NONE); + } +} +void LLPanelMediaHUD::onScrollRightHeld(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + this_panel->mScrollState = SCROLL_RIGHT; +} + +void LLPanelMediaHUD::onScrollLeft(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if(this_panel->mMediaImpl.notNull()) + { + this_panel->mMediaImpl->handleKeyHere(KEY_LEFT, MASK_NONE); + } +} +void LLPanelMediaHUD::onScrollLeftHeld(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + this_panel->mScrollState = SCROLL_LEFT; +} + +void LLPanelMediaHUD::onScrollDown(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + if(this_panel->mMediaImpl.notNull() && this_panel->mMediaImpl->hasMedia()) + { + this_panel->mMediaImpl->getMediaPlugin()->scrollEvent(0, 1, MASK_NONE); + } +} +void LLPanelMediaHUD::onScrollDownHeld(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + this_panel->mScrollState = SCROLL_DOWN; +} + +void LLPanelMediaHUD::onScrollStop(void* user_data) +{ + LLPanelMediaHUD* this_panel = static_cast<LLPanelMediaHUD*> (user_data); + this_panel->mScrollState = SCROLL_NONE; +} diff --git a/linden/indra/newview/llpanelmediahud.h b/linden/indra/newview/llpanelmediahud.h new file mode 100644 index 000000000..5f12ebcc5 --- /dev/null +++ b/linden/indra/newview/llpanelmediahud.h @@ -0,0 +1,110 @@ +/** + * @file llpanelmediahud.h + * @brief Media hud panel + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_PANELMEDIAHUD_H +#define LL_PANELMEDIAHUD_H + +#include "llpanel.h" +#include "llviewermedia.h" + +class LLCoordWindow; +class LLViewerMediaImpl; + +class LLPanelMediaHUD : public LLPanel +{ +public: + LLPanelMediaHUD(viewer_media_t media_impl); + virtual ~LLPanelMediaHUD(); + /*virtual*/ BOOL postBuild(); + virtual void draw(); + virtual void setAlpha(F32 alpha); + virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + void updateShape(); + bool isMouseOver(); + void setMediaFocus(bool b) { mMediaFocus = b; } + void nextZoomLevel(); + void resetZoomLevel() { mCurrentZoom = ZOOM_NONE; } + + LLHandle<LLPanelMediaHUD> getHandle() const { return mPanelHandle; } + void setMediaImpl(viewer_media_t media_impl) { mMediaImpl = media_impl; } + + + enum EZoomLevel + { + ZOOM_NONE = 0, + ZOOM_MEDIUM = 1, + ZOOM_END + }; + enum EScrollDir + { + SCROLL_UP = 0, + SCROLL_DOWN, + SCROLL_LEFT, + SCROLL_RIGHT, + SCROLL_NONE + }; + +private: + static void onClickClose(void* user_data); + static void onClickBack(void* user_data); + static void onClickForward(void* user_data); + static void onClickHome(void* user_data); + static void onClickOpen(void* user_data); + static void onClickReload(void* user_data); + static void onClickPlay(void* user_data); + static void onClickPause(void* user_data); + static void onClickStop(void* user_data); + static void onClickZoom(void* user_data); + static void onScrollUp(void* user_data); + static void onScrollUpHeld(void* user_data); + static void onScrollLeft(void* user_data); + static void onScrollLeftHeld(void* user_data); + static void onScrollRight(void* user_data); + static void onScrollRightHeld(void* user_data); + static void onScrollDown(void* user_data); + static void onScrollDownHeld(void* user_data); + static void onScrollStop(void* user_data); + + bool mMediaFocus; + LLMatrix4 mLastCameraMat; + EZoomLevel mCurrentZoom; + EScrollDir mScrollState; + LLCoordWindow mLastCursorPos; + LLFrameTimer mMouseMoveTimer; + LLFrameTimer mFadeTimer; + F32 mMouseInactiveTime; + F32 mControlFadeTime; + viewer_media_t mMediaImpl; + LLRootHandle<LLPanelMediaHUD> mPanelHandle; +}; + +#endif // LL_PANELMEDIAHUD_H diff --git a/linden/indra/newview/llpanelmsgs.cpp b/linden/indra/newview/llpanelmsgs.cpp index 3ea7aa573..9e04070e4 100644 --- a/linden/indra/newview/llpanelmsgs.cpp +++ b/linden/indra/newview/llpanelmsgs.cpp @@ -40,7 +40,7 @@ #include "lluictrlfactory.h" #include "llfirstuse.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" //----------------------------------------------------------------------------- LLPanelMsgs::LLPanelMsgs() : diff --git a/linden/indra/newview/llpanelobject.cpp b/linden/indra/newview/llpanelobject.cpp index 706f98e7f..cc89e24ff 100644 --- a/linden/indra/newview/llpanelobject.cpp +++ b/linden/indra/newview/llpanelobject.cpp @@ -76,7 +76,7 @@ #include "lldrawpool.h" -#include "hippoLimits.h" +#include "hippolimits.h" // [RLVa:KB] #include "rlvhandler.h" diff --git a/linden/indra/newview/llpanelpermissions.cpp b/linden/indra/newview/llpanelpermissions.cpp index 8492988ea..6b7bc1bad 100644 --- a/linden/indra/newview/llpanelpermissions.cpp +++ b/linden/indra/newview/llpanelpermissions.cpp @@ -68,7 +68,7 @@ #include "lluictrlfactory.h" #include "roles_constants.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // [RLVa:KB] #include "rlvhandler.h" @@ -281,7 +281,7 @@ void LLPanelPermissions::refresh() BOOL is_perm_modify = (LLSelectMgr::getInstance()->getSelection()->getFirstRootNode() && LLSelectMgr::getInstance()->selectGetRootsModify()) || LLSelectMgr::getInstance()->selectGetModify(); - const LLView* keyboard_focus_view = gFocusMgr.getKeyboardFocus(); + const LLFocusableElement* keyboard_focus_view = gFocusMgr.getKeyboardFocus(); S32 string_index = 0; std::string MODIFY_INFO_STRINGS[] = { diff --git a/linden/indra/newview/llpanelplace.cpp b/linden/indra/newview/llpanelplace.cpp index eb3d17da0..fe88c137e 100644 --- a/linden/indra/newview/llpanelplace.cpp +++ b/linden/indra/newview/llpanelplace.cpp @@ -58,7 +58,7 @@ #include "llweb.h" #include "llsdutil.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" //static std::list<LLPanelPlace*> LLPanelPlace::sAllPanels; diff --git a/linden/indra/newview/llpanelweb.cpp b/linden/indra/newview/llpanelweb.cpp index 38bb2d7b0..4a79493ce 100644 --- a/linden/indra/newview/llpanelweb.cpp +++ b/linden/indra/newview/llpanelweb.cpp @@ -37,51 +37,24 @@ // project includes #include "llcheckboxctrl.h" -#include "hippoGridManager.h" -#include "llmediamanager.h" +#include "hippogridmanager.h" #include "lluictrlfactory.h" #include "llviewercontrol.h" +#include "llviewermedia.h" #include "llviewerwindow.h" +#include "llpluginclassmedia.h" // helper functions for getting/freeing the web browser media // if creating/destroying these is too slow, we'll need to create // a static member and update all our static callbacks -LLMediaBase *get_web_media() +viewer_media_t get_web_media() { - LLMediaBase *media_source; - LLMediaManager *mgr = LLMediaManager::getInstance(); - - if (!mgr) - { - llwarns << "cannot get media manager" << llendl; - return NULL; - } - media_source = mgr->createSourceFromMimeType("http", "text/html" ); - if ( !media_source ) - { - llwarns << "media source create failed " << llendl; - return NULL; - } + viewer_media_t media_source = LLViewerMedia::newMediaImpl("", LLUUID::null, 0, 0, 0, 0, "text/html"); return media_source; } -void free_web_media(LLMediaBase *media_source) -{ - if (!media_source) - return; - - LLMediaManager *mgr = LLMediaManager::getInstance(); - if (!mgr) - { - llwarns << "cannot get media manager" << llendl; - return; - } - - mgr->destroySource(media_source); -} - LLPanelWeb::LLPanelWeb() { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_web.xml"); @@ -92,10 +65,11 @@ BOOL LLPanelWeb::postBuild() childSetAction("clear_cache", onClickClearCache, this); childSetCommitCallback("web_proxy_enabled", onCommitWebProxyEnabled, this); - std::string value = gSavedSettings.getBOOL("UseExternalBrowser") ? "external" : "internal"; + // MoonWorld: Always use external browser. + std::string value = "external"; childSetValue("use_external_browser", value); - childSetValue("cookies_enabled", gSavedSettings.getBOOL("CookiesEnabled")); + childSetValue("cookies_enabled", gSavedSettings.getBOOL("BrowserCookiesEnabled")); childSetValue("web_proxy_enabled", gSavedSettings.getBOOL("BrowserProxyEnabled")); childSetValue("web_proxy_editor", gSavedSettings.getString("BrowserProxyAddress")); @@ -128,7 +102,7 @@ LLPanelWeb::~LLPanelWeb() void LLPanelWeb::apply() { - gSavedSettings.setBOOL("CookiesEnabled", childGetValue("cookies_enabled")); + gSavedSettings.setBOOL("BrowserCookiesEnabled", childGetValue("cookies_enabled")); gSavedSettings.setBOOL("BrowserProxyEnabled", childGetValue("web_proxy_enabled")); gSavedSettings.setString("BrowserProxyAddress", childGetValue("web_proxy_editor")); gSavedSettings.setS32("BrowserProxyPort", childGetValue("web_proxy_port")); @@ -141,20 +115,20 @@ void LLPanelWeb::apply() gSavedSettings.setString("SearchURLQueryOpenSim", childGetValue("world_search_editor")); } - bool value = childGetValue("use_external_browser").asString() == "external" ? true : false; + // MoonWorld: Always use external browser. + bool value = true; gSavedSettings.setBOOL("UseExternalBrowser", value); - LLMediaBase *media_source = get_web_media(); - if (media_source) + viewer_media_t media_source = get_web_media(); + if (media_source && media_source->hasMedia()) { - media_source->enableCookies(childGetValue("cookies_enabled")); + media_source->getMediaPlugin()->enable_cookies(childGetValue("cookies_enabled")); bool proxy_enable = childGetValue("web_proxy_enabled"); std::string proxy_address = childGetValue("web_proxy_editor"); int proxy_port = childGetValue("web_proxy_port"); - media_source->enableProxy(proxy_enable, proxy_address, proxy_port); + media_source->getMediaPlugin()->proxy_setup(proxy_enable, proxy_address, proxy_port); } - free_web_media(media_source); } void LLPanelWeb::cancel() @@ -173,10 +147,9 @@ bool LLPanelWeb::callback_clear_browser_cache(const LLSD& notification, const LL S32 option = LLNotification::getSelectedOption(notification, response); if ( option == 0 ) // YES { - LLMediaBase *media_source = get_web_media(); - if (media_source) - media_source->clearCache(); - free_web_media(media_source); + viewer_media_t media_source = get_web_media(); + if (media_source && media_source->hasMedia()) + media_source->getMediaPlugin()->clear_cache(); } return false; } @@ -193,10 +166,9 @@ bool LLPanelWeb::callback_clear_cookies(const LLSD& notification, const LLSD& re S32 option = LLNotification::getSelectedOption(notification, response); if ( option == 0 ) // YES { - LLMediaBase *media_source = get_web_media(); - if (media_source) - media_source->clearCookies(); - free_web_media(media_source); + viewer_media_t media_source = get_web_media(); + if (media_source && media_source->hasMedia()) + media_source->getMediaPlugin()->clear_cookies(); } return false; } @@ -209,10 +181,9 @@ void LLPanelWeb::onCommitCookies(LLUICtrl* ctrl, void* data) if (!self || !check) return; - LLMediaBase *media_source = get_web_media(); - if (media_source) - media_source->enableCookies(check->get()); - free_web_media(media_source); + viewer_media_t media_source = get_web_media(); + if (media_source && media_source->hasMedia()) + media_source->getMediaPlugin()->enable_cookies(check->get()); } // static void LLPanelWeb::onCommitWebProxyEnabled(LLUICtrl* ctrl, void* data) @@ -255,4 +226,4 @@ void LLPanelWeb::onClickClear(void* user_data) { LLPanelWeb* self = (LLPanelWeb*)user_data; self->childSetValue("world_search_editor","") ; -} \ No newline at end of file +} diff --git a/linden/indra/newview/llprefsadvanced.cpp b/linden/indra/newview/llprefsadvanced.cpp index aa62b3445..643db377f 100644 --- a/linden/indra/newview/llprefsadvanced.cpp +++ b/linden/indra/newview/llprefsadvanced.cpp @@ -100,8 +100,9 @@ BOOL LLPrefsAdvanced::postBuild() childSetValue("shadows_check", gSavedSettings.getBOOL("ShadowsEnabled")); childSetValue("command_line_check", gSavedSettings.getBOOL("CmdLineChatbarEnabled")); - childSetValue("lightshare_combo", - LLSD((S32)gSavedSettings.getU32("LightShareAllowed"))); + // MoonWorld: this setting is disabled. The combo box doesn't exist anymore. + //childSetValue("lightshare_combo", + // LLSD((S32)gSavedSettings.getU32("LightShareAllowed"))); LLComboBox* crash_behavior_combobox = getChild<LLComboBox>("crash_behavior_combobox"); crash_behavior_combobox->setCurrentByIndex(gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING)); @@ -116,15 +117,6 @@ BOOL LLPrefsAdvanced::postBuild() initHelpBtn("EmeraldHelp_SpellCheck", "EmeraldHelp_SpellCheck"); - childSetValue("HighlightOwnNameInIM", gSavedSettings.getBOOL("HighlightOwnNameInIM")); - childSetValue("HighlightFriendsChat", gSavedSettings.getBOOL("HighlightFriendsChat")); - getChild<LLColorSwatchCtrl>("FriendsChatColor")->set(gSavedSettings.getColor4("FriendsChatColor")); - childSetValue("HighlightOwnNameInChat", gSavedSettings.getBOOL("HighlightOwnNameInChat")); - getChild<LLColorSwatchCtrl>("OwnNameChatColor")->set(gSavedSettings.getColor4("OwnNameChatColor")); - childSetValue("nick01", gSavedSettings.getString("nick01")); - childSetValue("nick02", gSavedSettings.getString("nick02")); - childSetValue("nick03", gSavedSettings.getString("nick03")); - refresh(); return TRUE; @@ -144,26 +136,8 @@ void LLPrefsAdvanced::apply() gSavedSettings.setBOOL("LanguageIsPublic", childGetValue("language_is_public")); gSavedSettings.setBOOL("AllowMUpose", childGetValue("allow_mupose")); gSavedSettings.setBOOL("AutoCloseOOC", childGetValue("auto_close_ooc")); - gSavedSettings.setU32("LightShareAllowed", - (U32)childGetValue("lightshare_combo").asInteger()); - - gSavedSettings.setBOOL("HighlightOwnNameInIM", childGetValue("HighlightOwnNameInIM")); - gSavedSettings.setBOOL("HighlightFriendsChat", childGetValue("HighlightFriendsChat")); - gSavedSettings.setColor4("FriendsChatColor", getChild<LLColorSwatchCtrl>("FriendsChatColor")->get()); - gSavedSettings.setBOOL("HighlightOwnNameInChat", childGetValue("HighlightOwnNameInChat")); - gSavedSettings.setColor4("OwnNameChatColor", getChild<LLColorSwatchCtrl>("OwnNameChatColor")->get()); - - std::string nick01 = childGetValue("nick01"); - boost::trim(nick01); - gSavedSettings.setString("nick01", nick01); - - std::string nick02 = childGetValue("nick02"); - boost::trim(nick02); - gSavedSettings.setString("nick02", nick02); - - std::string nick03 = childGetValue("nick03"); - boost::trim(nick03); - gSavedSettings.setString("nick03", nick03); + // MoonWorld: this setting is disabled. The combo box doesn't exist anymore. + //gSavedSettings.setU32("LightShareAllowed", (U32)childGetValue("lightshare_combo").asInteger()); // Need to force a rebake when ClothingLayerProtection toggled for it take effect -- MC if (gSavedSettings.getBOOL("ShowMyClientTagToOthers") != (BOOL)childGetValue("client_name_tag_broadcast_check")) diff --git a/linden/indra/newview/llprefschat.cpp b/linden/indra/newview/llprefschat.cpp index 6ebc8809c..5f74a2511 100644 --- a/linden/indra/newview/llprefschat.cpp +++ b/linden/indra/newview/llprefschat.cpp @@ -36,10 +36,8 @@ #include "llchatbar.h" #include "llfloaterchat.h" #include "llprefschat.h" -#include "lltexteditor.h" #include "llviewercontrol.h" #include "lluictrlfactory.h" -#include "llcolorswatch.h" #include "llradiogroup.h" #include "llstylemap.h" @@ -57,21 +55,13 @@ class LLPrefsChatImpl : public LLPanel S32 mChatSize; F32 mChatPersist; S32 mChatMaxLines; - LLColor4 mSystemChatColor; - LLColor4 mUserChatColor; - LLColor4 mAgentChatColor; - LLColor4 mIMChatColor; - LLColor4 mObjectChatColor; - LLColor4 mOwnerSayChatColor; - LLColor4 mBGChatColor; - LLColor4 mScriptErrorColor; - LLColor4 mHTMLLinkColor; BOOL mChatFullWidth; BOOL mCloseChatOnReturn; BOOL mArrowKeysMoveAvatar; BOOL mShowTimestamps; BOOL mPlayTypingAnim; BOOL mChatBubbles; + BOOL mLocalChatBubbles; BOOL mScriptErrorAsChat; BOOL mChatChannel; F32 mConsoleOpacity; @@ -91,21 +81,12 @@ LLPrefsChatImpl::LLPrefsChatImpl() childSetValue("fade_chat_time", gSavedSettings.getF32("ChatPersistTime")); childSetValue("max_chat_count", gSavedSettings.getS32("ConsoleMaxLines")); - getChild<LLColorSwatchCtrl>("system")->set(gSavedSettings.getColor4("SystemChatColor")); - getChild<LLColorSwatchCtrl>("user")->set(gSavedSettings.getColor4("UserChatColor")); - getChild<LLColorSwatchCtrl>("agent")->set(gSavedSettings.getColor4("AgentChatColor")); - getChild<LLColorSwatchCtrl>("im")->set(gSavedSettings.getColor4("IMChatColor")); - getChild<LLColorSwatchCtrl>("script_error")->set(gSavedSettings.getColor4("ScriptErrorColor")); - getChild<LLColorSwatchCtrl>("objects")->set(gSavedSettings.getColor4("ObjectChatColor")); - getChild<LLColorSwatchCtrl>("owner")->set(gSavedSettings.getColor4("llOwnerSayChatColor")); - getChild<LLColorSwatchCtrl>("background")->set(gSavedSettings.getColor4("BackgroundChatColor")); - getChild<LLColorSwatchCtrl>("links")->set(gSavedSettings.getColor4("HTMLLinkColor")); - childSetValue("arrow_keys_move_avatar_check", gSavedSettings.getBOOL("ArrowKeysMoveAvatar")); childSetValue("show_timestamps_check", gSavedSettings.getBOOL("ChatShowTimestamps")); childSetValue("script_errors_as_chat", gSavedSettings.getBOOL("ScriptErrorsAsChat")); childSetValue("bubble_text_chat", gSavedSettings.getBOOL("UseChatBubbles")); + childSetValue("local_bubble_text_chat", gSavedSettings.getBOOL("UseLocalChatWithBubbles")); childSetValue("chat_full_width_check", gSavedSettings.getBOOL("ChatFullWidth")); childSetValue("close_chat_on_return_check", gSavedSettings.getBOOL("CloseChatOnReturn")); childSetValue("play_typing_animation", gSavedSettings.getBOOL("PlayTypingAnim")); @@ -122,19 +103,11 @@ void LLPrefsChatImpl::refreshValues() mChatSize = gSavedSettings.getS32("ChatFontSize"); mChatPersist = gSavedSettings.getF32("ChatPersistTime"); mChatMaxLines = gSavedSettings.getS32("ConsoleMaxLines"); - mSystemChatColor = gSavedSettings.getColor4("SystemChatColor"); - mUserChatColor = gSavedSettings.getColor4("UserChatColor"); - mAgentChatColor = gSavedSettings.getColor4("AgentChatColor"); - mIMChatColor = gSavedSettings.getColor4("IMChatColor"); - mObjectChatColor = gSavedSettings.getColor4("ObjectChatColor"); - mOwnerSayChatColor = gSavedSettings.getColor4("llOwnerSayChatColor"); - mBGChatColor = gSavedSettings.getColor4("BackgroundChatColor"); - mScriptErrorColor = gSavedSettings.getColor4("ScriptErrorColor"); - mHTMLLinkColor = gSavedSettings.getColor4("HTMLLinkColor"); mArrowKeysMoveAvatar = gSavedSettings.getBOOL("ArrowKeysMoveAvatar"); mShowTimestamps = gSavedSettings.getBOOL("ChatShowTimestamps"); mScriptErrorAsChat = gSavedSettings.getBOOL("ScriptErrorsAsChat"); mChatBubbles = gSavedSettings.getBOOL("UseChatBubbles"); + mLocalChatBubbles = gSavedSettings.getBOOL("UseLocalChatWithBubbles"); mChatFullWidth = gSavedSettings.getBOOL("ChatFullWidth"); mCloseChatOnReturn = gSavedSettings.getBOOL("CloseChatOnReturn"); mPlayTypingAnim = gSavedSettings.getBOOL("PlayTypingAnim"); @@ -151,19 +124,11 @@ void LLPrefsChatImpl::cancel() gSavedSettings.setS32("ChatFontSize", mChatSize); gSavedSettings.setF32("ChatPersistTime", mChatPersist); gSavedSettings.setS32("ConsoleMaxLines", mChatMaxLines); - gSavedSettings.setColor4("SystemChatColor", mSystemChatColor); - gSavedSettings.setColor4("UserChatColor", mUserChatColor); - gSavedSettings.setColor4("AgentChatColor", mAgentChatColor); - gSavedSettings.setColor4("IMChatColor", mIMChatColor); - gSavedSettings.setColor4("ObjectChatColor", mObjectChatColor); - gSavedSettings.setColor4("llOwnerSayChatColor", mOwnerSayChatColor); - gSavedSettings.setColor4("BackgroundChatColor", mBGChatColor); - gSavedSettings.setColor4("ScriptErrorColor", mScriptErrorColor); - gSavedSettings.setColor4("HTMLLinkColor", mHTMLLinkColor); gSavedSettings.setBOOL("ArrowKeysMoveAvatar", mArrowKeysMoveAvatar); gSavedSettings.setBOOL("ChatShowTimestamps", mShowTimestamps); gSavedSettings.setBOOL("ScriptErrorsAsChat", mScriptErrorAsChat); gSavedSettings.setBOOL("UseChatBubbles", mChatBubbles); + gSavedSettings.setBOOL("UseLocalChatWithBubbles", mLocalChatBubbles); gSavedSettings.setBOOL("ChatFullWidth", mChatFullWidth); gSavedSettings.setBOOL("CloseChatOnReturn", mCloseChatOnReturn); gSavedSettings.setBOOL("PlayTypingAnim", mPlayTypingAnim); @@ -180,22 +145,11 @@ void LLPrefsChatImpl::apply() gSavedSettings.setF32("ChatPersistTime", childGetValue("fade_chat_time").asReal()); gSavedSettings.setS32("ConsoleMaxLines", childGetValue("max_chat_count")); - gSavedSettings.setColor4("SystemChatColor", childGetValue("system")); - gSavedSettings.setColor4("UserChatColor", childGetValue("user")); - gSavedSettings.setColor4("AgentChatColor", childGetValue("agent")); - gSavedSettings.setColor4("IMChatColor", childGetValue("im")); - gSavedSettings.setColor4("ScriptErrorColor", childGetValue("script_error")); - gSavedSettings.setColor4("ObjectChatColor", childGetValue("objects")); - gSavedSettings.setColor4("llOwnerSayChatColor", childGetValue("owner")); - gSavedSettings.setColor4("BackgroundChatColor", childGetValue("background")); - - gSavedSettings.setColor4("HTMLLinkColor", childGetValue("links")); - LLTextEditor::setLinkColor(childGetValue("links")); - gSavedSettings.setBOOL("ArrowKeysMoveAvatar", childGetValue("arrow_keys_move_avatar_check")); gSavedSettings.setBOOL("ChatShowTimestamps", childGetValue("show_timestamps_check")); gSavedSettings.setBOOL("ScriptErrorsAsChat", childGetValue("script_errors_as_chat")); gSavedSettings.setBOOL("UseChatBubbles", childGetValue("bubble_text_chat")); + gSavedSettings.setBOOL("UseLocalChatWithBubbles", childGetValue("local_bubble_text_chat")); gSavedSettings.setBOOL("ChatFullWidth", childGetValue("chat_full_width_check")); gSavedSettings.setBOOL("CloseChatOnReturn", childGetValue("close_chat_on_return_check")); gSavedSettings.setBOOL("PlayTypingAnim", childGetValue("play_typing_animation")); diff --git a/linden/indra/newview/llprefscolors.cpp b/linden/indra/newview/llprefscolors.cpp new file mode 100644 index 000000000..b0bc34510 --- /dev/null +++ b/linden/indra/newview/llprefscolors.cpp @@ -0,0 +1,181 @@ +/** +* @file llprefscolors.cpp +* @brief Color-specific preferences for Imprudence +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2010, McCabe Maxsted +* +* Imprudence Viewer Source Code +* The source code in this file ("Source Code") is provided to you +* under the terms of the GNU General Public License, version 2.0 +* ("GPL"). Terms of the GPL can be found in doc/GPL-license.txt in +* this distribution, or online at +* http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL SOURCE CODE IS PROVIDED "AS IS." THE AUTHOR MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llprefscolors.h" +#include "lltexteditor.h" +#include "llviewercontrol.h" + +#include "lluictrlfactory.h" +#include "llcolorswatch.h" + +#include "boost/algorithm/string.hpp" + +LLPrefsColors::LLPrefsColors() +{ + refreshColors(); // initialize member data from saved settings + + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_colors.xml"); +} + +LLPrefsColors::~LLPrefsColors() +{ + // Children all cleaned up by default view destructor. +} + +BOOL LLPrefsColors::postBuild() +{ + getChild<LLColorSwatchCtrl>("system")->set(gSavedSettings.getColor4("SystemChatColor")); + getChild<LLColorSwatchCtrl>("user")->set(gSavedSettings.getColor4("UserChatColor")); + getChild<LLColorSwatchCtrl>("agent")->set(gSavedSettings.getColor4("AgentChatColor")); + getChild<LLColorSwatchCtrl>("im")->set(gSavedSettings.getColor4("IMChatColor")); + getChild<LLColorSwatchCtrl>("script_error")->set(gSavedSettings.getColor4("ScriptErrorColor")); + getChild<LLColorSwatchCtrl>("objects")->set(gSavedSettings.getColor4("ObjectChatColor")); + getChild<LLColorSwatchCtrl>("owner")->set(gSavedSettings.getColor4("llOwnerSayChatColor")); + getChild<LLColorSwatchCtrl>("background")->set(gSavedSettings.getColor4("BackgroundChatColor")); + getChild<LLColorSwatchCtrl>("links")->set(gSavedSettings.getColor4("HTMLLinkColor")); + getChild<LLColorSwatchCtrl>("FriendsChatColor")->set(gSavedSettings.getColor4("FriendsChatColor")); + getChild<LLColorSwatchCtrl>("OwnNameChatColor")->set(gSavedSettings.getColor4("OwnNameChatColor")); + + childSetValue("HighlightOwnNameInIM", gSavedSettings.getBOOL("HighlightOwnNameInIM")); + childSetValue("HighlightFriendsChat", gSavedSettings.getBOOL("HighlightFriendsChat")); + childSetValue("HighlightOwnNameInChat", gSavedSettings.getBOOL("HighlightOwnNameInChat")); + updateSelfCheck(); + updateFriendsCheck(); + + // All three of these settings must exist, they are read by LLFloaterChat::isOwnNameInText. + childSetValue("nick01", gSavedSettings.getString("HighlightNickname01")); + childSetValue("nick02", gSavedSettings.getString("HighlightNickname02")); + childSetValue("nick03", gSavedSettings.getString("HighlightNickname03")); + + childSetCommitCallback("HighlightOwnNameInIM", onCommitCheckSelfName, this); + childSetCommitCallback("HighlightOwnNameInChat", onCommitCheckSelfName, this); + childSetCommitCallback("HighlightFriendsChat", onCommitCheckFriends, this); + + return TRUE; +} + +void LLPrefsColors::refreshColors() +{ + mSystemChatColor = gSavedSettings.getColor4("SystemChatColor"); + mUserChatColor = gSavedSettings.getColor4("UserChatColor"); + mAgentChatColor = gSavedSettings.getColor4("AgentChatColor"); + mIMChatColor = gSavedSettings.getColor4("IMChatColor"); + mObjectChatColor = gSavedSettings.getColor4("ObjectChatColor"); + mOwnerSayChatColor = gSavedSettings.getColor4("llOwnerSayChatColor"); + mBGChatColor = gSavedSettings.getColor4("BackgroundChatColor"); + mScriptErrorColor = gSavedSettings.getColor4("ScriptErrorColor"); + mHTMLLinkColor = gSavedSettings.getColor4("HTMLLinkColor"); + mFriendsChatColor = gSavedSettings.getColor4("FriendsChatColor"); + mOwnNameChatColor = gSavedSettings.getColor4("OwnNameChatColor"); +} + +// static +void LLPrefsColors::onCommitCheckSelfName(LLUICtrl* ctrl, void* userdata) +{ + LLPrefsColors* self = (LLPrefsColors*)userdata; + self->updateSelfCheck(); +} + +void LLPrefsColors::updateSelfCheck() +{ + bool highlight_names_enabled = (childGetValue("HighlightOwnNameInIM") || childGetValue("HighlightOwnNameInChat")); + + getChild<LLColorSwatchCtrl>("OwnNameChatColor")->setEnabled(highlight_names_enabled); + childSetEnabled("nick01", highlight_names_enabled); + childSetEnabled("nick02", highlight_names_enabled); + childSetEnabled("nick03", highlight_names_enabled); + childSetEnabled("nick01_text", highlight_names_enabled); + childSetEnabled("nick02_text", highlight_names_enabled); + childSetEnabled("nick03_text", highlight_names_enabled); +} + +// static +void LLPrefsColors::onCommitCheckFriends(LLUICtrl* ctrl, void* userdata) +{ + LLPrefsColors* self = (LLPrefsColors*)userdata; + self->updateFriendsCheck(); +} + +void LLPrefsColors::updateFriendsCheck() +{ + getChild<LLColorSwatchCtrl>("FriendsChatColor")->setEnabled(childGetValue("HighlightFriendsChat")); +} + +void LLPrefsColors::cancel() +{ + gSavedSettings.setColor4("SystemChatColor", mSystemChatColor); + gSavedSettings.setColor4("UserChatColor", mUserChatColor); + gSavedSettings.setColor4("AgentChatColor", mAgentChatColor); + gSavedSettings.setColor4("IMChatColor", mIMChatColor); + gSavedSettings.setColor4("ObjectChatColor", mObjectChatColor); + gSavedSettings.setColor4("llOwnerSayChatColor", mOwnerSayChatColor); + gSavedSettings.setColor4("BackgroundChatColor", mBGChatColor); + gSavedSettings.setColor4("ScriptErrorColor", mScriptErrorColor); + gSavedSettings.setColor4("HTMLLinkColor", mHTMLLinkColor); + gSavedSettings.setColor4("FriendsChatColor", mFriendsChatColor); + gSavedSettings.setColor4("OwnNameChatColor", mOwnNameChatColor); +} + +void LLPrefsColors::apply() +{ + gSavedSettings.setColor4("SystemChatColor", childGetValue("system")); + gSavedSettings.setColor4("UserChatColor", childGetValue("user")); + gSavedSettings.setColor4("AgentChatColor", childGetValue("agent")); + gSavedSettings.setColor4("IMChatColor", childGetValue("im")); + gSavedSettings.setColor4("ScriptErrorColor", childGetValue("script_error")); + gSavedSettings.setColor4("ObjectChatColor", childGetValue("objects")); + gSavedSettings.setColor4("llOwnerSayChatColor", childGetValue("owner")); + gSavedSettings.setColor4("BackgroundChatColor", childGetValue("background")); + + gSavedSettings.setColor4("HTMLLinkColor", childGetValue("links")); + LLTextEditor::setLinkColor(childGetValue("links")); + + gSavedSettings.setBOOL("HighlightOwnNameInIM", childGetValue("HighlightOwnNameInIM")); + gSavedSettings.setBOOL("HighlightFriendsChat", childGetValue("HighlightFriendsChat")); + gSavedSettings.setColor4("FriendsChatColor", getChild<LLColorSwatchCtrl>("FriendsChatColor")->get()); + gSavedSettings.setBOOL("HighlightOwnNameInChat", childGetValue("HighlightOwnNameInChat")); + gSavedSettings.setColor4("OwnNameChatColor", getChild<LLColorSwatchCtrl>("OwnNameChatColor")->get()); + + std::string nick01 = childGetValue("nick01"); + boost::trim(nick01); + gSavedSettings.setString("HighlightNickname01", nick01); + + std::string nick02 = childGetValue("nick02"); + boost::trim(nick02); + gSavedSettings.setString("HighlightNickname02", nick02); + + std::string nick03 = childGetValue("nick03"); + boost::trim(nick03); + gSavedSettings.setString("HighlightNickname03", nick03); + + refreshColors(); // member values become the official values and cancel becomes a no-op. +} diff --git a/linden/indra/newview/llprefscolors.h b/linden/indra/newview/llprefscolors.h new file mode 100644 index 000000000..70bda8977 --- /dev/null +++ b/linden/indra/newview/llprefscolors.h @@ -0,0 +1,67 @@ +/** +* @file llprefscolors.h +* @brief Advanced preferences options for Imprudence +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2010, McCabe Maxsted +* +* Imprudence Viewer Source Code +* The source code in this file ("Source Code") is provided to you +* under the terms of the GNU General Public License, version 2.0 +* ("GPL"). Terms of the GPL can be found in doc/GPL-license.txt in +* this distribution, or online at +* http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL SOURCE CODE IS PROVIDED "AS IS." THE AUTHOR MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#ifndef LLPREFSCOLORS_H +#define LLPREFSCOLORS_H + +#include "llpanel.h" + +class LLPrefsColors : public LLPanel +{ +public: + LLPrefsColors(); + ~LLPrefsColors(); + + BOOL postBuild(); + + void apply(); + void cancel(); + +private: + static void onCommitCheckSelfName(LLUICtrl* ctrl, void* userdata); + static void onCommitCheckFriends(LLUICtrl* ctrl, void* userdata); + void refreshColors(); + void updateFriendsCheck(); + void updateSelfCheck(); + + LLColor4 mSystemChatColor; + LLColor4 mUserChatColor; + LLColor4 mAgentChatColor; + LLColor4 mIMChatColor; + LLColor4 mObjectChatColor; + LLColor4 mOwnerSayChatColor; + LLColor4 mBGChatColor; + LLColor4 mScriptErrorColor; + LLColor4 mHTMLLinkColor; + LLColor4 mFriendsChatColor; + LLColor4 mOwnNameChatColor; +}; + +#endif //LLPREFSCOLORS_H diff --git a/linden/indra/newview/llprefsim.cpp b/linden/indra/newview/llprefsim.cpp index 2c8ef4d05..9e86cd348 100644 --- a/linden/indra/newview/llprefsim.cpp +++ b/linden/indra/newview/llprefsim.cpp @@ -45,10 +45,11 @@ #include "llviewercontrol.h" #include "llviewernetwork.h" #include "lluictrlfactory.h" +#include "llstartup.h" #include "lldirpicker.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" // [RLVa:KB] #include "rlvhandler.h" @@ -106,22 +107,23 @@ BOOL LLPrefsIMImpl::postBuild() childSetLabelArg("send_im_to_email", "[EMAIL]", getString("log_in_to_change")); // Don't enable this until we get personal data - childDisable("include_im_in_chat_console"); - childDisable("include_im_in_chat_history"); - childDisable("show_timestamps_check"); - childDisable("friends_online_notify_checkbox"); + // Unless we're already logged in. Some non-SL grids won't send us the data we need -- MC + childSetEnabled("include_im_in_chat_console", LLStartUp::isLoggedIn()); + childSetEnabled("include_im_in_chat_history", LLStartUp::isLoggedIn()); + childSetEnabled("show_timestamps_check", LLStartUp::isLoggedIn()); + childSetEnabled("friends_online_notify_checkbox", LLStartUp::isLoggedIn()); - childDisable("online_visibility"); - childDisable("send_im_to_email"); - childDisable("log_instant_messages"); - childDisable("log_chat"); - childDisable("log_show_history"); - childDisable("log_path_button"); - childDisable("busy_response"); - childDisable("log_instant_messages_timestamp"); - childDisable("log_chat_timestamp"); - childDisable("log_chat_IM"); - childDisable("log_date_timestamp"); + childSetEnabled("online_visibility", LLStartUp::isLoggedIn()); + childSetEnabled("send_im_to_email", LLStartUp::isLoggedIn()); + childSetEnabled("log_instant_messages", LLStartUp::isLoggedIn()); + childSetEnabled("log_chat", LLStartUp::isLoggedIn()); + childSetEnabled("log_show_history", LLStartUp::isLoggedIn()); + childSetEnabled("log_path_button", LLStartUp::isLoggedIn()); + childSetEnabled("busy_response", LLStartUp::isLoggedIn()); + childSetEnabled("log_instant_messages_timestamp", LLStartUp::isLoggedIn()); + childSetEnabled("log_chat_timestamp", LLStartUp::isLoggedIn()); + childSetEnabled("log_chat_IM", LLStartUp::isLoggedIn()); + childSetEnabled("log_date_timestamp", LLStartUp::isLoggedIn()); childSetText("busy_response", getString("log_in_to_change")); diff --git a/linden/indra/newview/llprefsvoice.cpp b/linden/indra/newview/llprefsvoice.cpp index fe5446ba2..7c50f4acd 100644 --- a/linden/indra/newview/llprefsvoice.cpp +++ b/linden/indra/newview/llprefsvoice.cpp @@ -153,8 +153,8 @@ void LLPrefsVoice::apply() if (enable_voice && !gSavedSettings.getBOOL("VivoxLicenseAccepted")) { // This window enables voice chat if license is accepted - FloaterVoiceLicense::getInstance()->open(); - FloaterVoiceLicense::getInstance()->center(); + FloaterVoiceLicense::getInstance()->open(); + FloaterVoiceLicense::getInstance()->center(); } else { diff --git a/linden/indra/newview/llpreviewscript.cpp b/linden/indra/newview/llpreviewscript.cpp index 98a5d8f33..813be03dc 100644 --- a/linden/indra/newview/llpreviewscript.cpp +++ b/linden/indra/newview/llpreviewscript.cpp @@ -81,7 +81,7 @@ #include "llviewertexteditor.h" #include "llviewerwindow.h" #include "lluictrlfactory.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" #include "lluictrlfactory.h" #include "llviewercontrol.h" @@ -363,7 +363,7 @@ void LLScriptEdCore::updateDynamicHelp(BOOL immediate) // update back and forward buttons LLButton* fwd_button = help_floater->getChild<LLButton>("fwd_btn"); LLButton* back_button = help_floater->getChild<LLButton>("back_btn"); - LLWebBrowserCtrl* browser = help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html"); + LLMediaCtrl* browser = help_floater->getChild<LLMediaCtrl>("lsl_guide_html"); back_button->setEnabled(browser->canNavigateBack()); fwd_button->setEnabled(browser->canNavigateForward()); @@ -422,7 +422,7 @@ void LLScriptEdCore::setHelpPage(const std::string& help_string) LLFloater* help_floater = mLiveHelpHandle.get(); if (!help_floater) return; - LLWebBrowserCtrl* web_browser = help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html"); + LLMediaCtrl* web_browser = help_floater->getChild<LLMediaCtrl>("lsl_guide_html"); if (!web_browser) return; LLComboBox* history_combo = help_floater->getChild<LLComboBox>("history_combo"); @@ -546,7 +546,8 @@ bool LLScriptEdCore::onHelpAutoscript(const LLSD& notification, const LLSD& resp switch(option) { case 0: - LLWeb::loadURLInternal(notification["payload"]["autoscript_url"]); + // MoonWorld: Open even script help in the external browser instead of the internal browser. + LLWeb::loadURL(notification["payload"]["autoscript_url"]); break; default: break; @@ -595,7 +596,7 @@ void LLScriptEdCore::onBtnDynamicHelp(void* userdata) live_help_floater->childSetAction("back_btn", onClickBack, userdata); live_help_floater->childSetAction("fwd_btn", onClickForward, userdata); - LLWebBrowserCtrl* browser = live_help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html"); + LLMediaCtrl* browser = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html"); browser->setAlwaysRefresh(TRUE); LLComboBox* help_combo = live_help_floater->getChild<LLComboBox>("history_combo"); @@ -624,7 +625,7 @@ void LLScriptEdCore::onClickBack(void* userdata) LLFloater* live_help_floater = corep->mLiveHelpHandle.get(); if (live_help_floater) { - LLWebBrowserCtrl* browserp = live_help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html"); + LLMediaCtrl* browserp = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html"); if (browserp) { browserp->navigateBack(); @@ -639,7 +640,7 @@ void LLScriptEdCore::onClickForward(void* userdata) LLFloater* live_help_floater = corep->mLiveHelpHandle.get(); if (live_help_floater) { - LLWebBrowserCtrl* browserp = live_help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html"); + LLMediaCtrl* browserp = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html"); if (browserp) { browserp->navigateForward(); @@ -681,7 +682,7 @@ void LLScriptEdCore::onHelpComboCommit(LLUICtrl* ctrl, void* userdata) corep->addHelpItemToHistory(help_string); - LLWebBrowserCtrl* web_browser = live_help_floater->getChild<LLWebBrowserCtrl>("lsl_guide_html"); + LLMediaCtrl* web_browser = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html"); LLUIString url_string = gSavedSettings.getString("LSLHelpURL"); url_string.setArg("[APP_DIRECTORY]", gDirUtilp->getWorkingDir()); url_string.setArg("[LSL_STRING]", help_string); diff --git a/linden/indra/newview/llpreviewsound.cpp b/linden/indra/newview/llpreviewsound.cpp index 26d8da5a6..0dd65ab0e 100644 --- a/linden/indra/newview/llpreviewsound.cpp +++ b/linden/indra/newview/llpreviewsound.cpp @@ -32,7 +32,7 @@ #include "llviewerprecompiledheaders.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llagent.h" // gAgent #include "llbutton.h" #include "llinventory.h" diff --git a/linden/indra/newview/llselectmgr.cpp b/linden/indra/newview/llselectmgr.cpp index 5a10e98e7..6496ff376 100644 --- a/linden/indra/newview/llselectmgr.cpp +++ b/linden/indra/newview/llselectmgr.cpp @@ -59,6 +59,7 @@ #include "llfloaterreporter.h" #include "llfloatertools.h" #include "llframetimer.h" +#include "llfocusmgr.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" #include "llinventorymodel.h" @@ -75,6 +76,8 @@ #include "llviewercamera.h" #include "llviewercontrol.h" #include "llviewerimagelist.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h" #include "llviewermenu.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" @@ -82,6 +85,8 @@ #include "llviewerregion.h" #include "llviewerstats.h" #include "llvoavatar.h" +#include "llvograss.h" +#include "llvotree.h" #include "llvovolume.h" #include "pipeline.h" @@ -829,7 +834,10 @@ void LLSelectMgr::highlightObjectOnly(LLViewerObject* objectp) return; } - if (objectp->getPCode() != LL_PCODE_VOLUME) + if ((objectp->getPCode() != LL_PCODE_VOLUME) && + (objectp->getPCode() != LL_PCODE_LEGACY_TREE) && + (objectp->getPCode() != LL_PCODE_LEGACY_GRASS)) + { return; } @@ -877,7 +885,10 @@ void LLSelectMgr::highlightObjectAndFamily(const std::vector<LLViewerObject*>& o { continue; } - if (object->getPCode() != LL_PCODE_VOLUME) + + if ((object->getPCode() != LL_PCODE_VOLUME) && + (object->getPCode() != LL_PCODE_LEGACY_TREE) && + (object->getPCode() != LL_PCODE_LEGACY_GRASS)) { continue; } @@ -897,7 +908,14 @@ void LLSelectMgr::highlightObjectAndFamily(const std::vector<LLViewerObject*>& o void LLSelectMgr::unhighlightObjectOnly(LLViewerObject* objectp) { - if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME)) + if (!objectp) + { + return; + } + + if ((objectp->getPCode() != LL_PCODE_VOLUME) && + (objectp->getPCode() != LL_PCODE_LEGACY_TREE) && + (objectp->getPCode() != LL_PCODE_LEGACY_GRASS)) { return; } @@ -1718,7 +1736,7 @@ void LLSelectMgr::selectionSetMediaTypeAndURL(U8 media_type, const std::string& U8 media_flags = LLTextureEntry::MF_NONE; if (media_type == LLViewerObject::MEDIA_TYPE_WEB_PAGE) { - media_flags = LLTextureEntry::MF_WEB_PAGE; + media_flags = LLTextureEntry::MF_HAS_MEDIA; } struct f : public LLSelectedTEFunctor @@ -1861,7 +1879,7 @@ BOOL LLSelectMgr::selectionAllPCode(LLPCode code) f(const LLPCode& t) : mCode(t) {} virtual bool apply(LLViewerObject* object) { - if (object->getPCode() != mCode) + if (object->getPCode() != mCode && !gSavedSettings.getBOOL("AllowEditingOfTrees")) { return FALSE; } @@ -3463,7 +3481,7 @@ void LLSelectMgr::deselectAllIfTooFar() // HACK: Don't deselect when we're navigating to rate an object's // owner or creator. JC - if (gPieObject->getVisible()) + if (gPieObject && gPieObject->getVisible()) { return; } @@ -4923,7 +4941,7 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud) if (mSelectedObjects->getNumNodes()) { LLUUID inspect_item_id = LLFloaterInspect::getSelectedUUID(); - + LLUUID focus_item_id = LLViewerMediaFocus::getInstance()->getSelectedUUID(); for (S32 pass = 0; pass < 2; pass++) { for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); @@ -4937,7 +4955,11 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud) { continue; } - if(objectp->getID() == inspect_item_id) + if (objectp->getID() == focus_item_id) + { + node->renderOneSilhouette(gFocusMgr.getFocusColor()); + } + else if(objectp->getID() == inspect_item_id) { node->renderOneSilhouette(sHighlightInspectColor); } @@ -5013,6 +5035,14 @@ void LLSelectMgr::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_ { ((LLVOVolume*)objectp)->generateSilhouette(nodep, view_point); } + else if (objectp && objectp->getPCode() == LL_PCODE_LEGACY_GRASS) + { + ((LLVOGrass*)objectp)->generateSilhouette(nodep, view_point); + } + else if (objectp && objectp->getPCode() == LL_PCODE_LEGACY_TREE) + { + ((LLVOTree*)objectp)->generateSilhouette(nodep, view_point); + } } // @@ -5348,8 +5378,10 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) glMultMatrixf((F32*) objectp->getRenderMatrix().mMatrix); } - LLVolume *volume = objectp->getVolume(); - if (volume) + //LLVolume *volume = objectp->getVolume(); + //if (volume) + // we used to only call this for volumes. but let's render silhouettes for any node that has them. + if (1) { F32 silhouette_thickness; if (is_hud_object && gAgent.getAvatarObject()) @@ -5473,12 +5505,12 @@ void dialog_refresh_all() gFloaterTools->dirty(); - if( gPieObject->getVisible() ) + if( gPieObject && gPieObject->getVisible() ) { gPieObject->arrange(); } - if( gPieAttachment->getVisible() ) + if( gPieAttachment && gPieAttachment->getVisible() ) { gPieAttachment->arrange(); } diff --git a/linden/indra/newview/llspatialpartition.cpp b/linden/indra/newview/llspatialpartition.cpp index c1d5ff309..d9fa5b512 100644 --- a/linden/indra/newview/llspatialpartition.cpp +++ b/linden/indra/newview/llspatialpartition.cpp @@ -826,7 +826,7 @@ class LLSpatialSetStateDiff : public LLSpatialSetState public: LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { } - virtual void traverse(const LLSpatialGroup::TreeNode* n) + virtual void traverse(const LLSpatialGroup::OctreeNode* n) { LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); @@ -885,7 +885,7 @@ class LLSpatialClearStateDiff : public LLSpatialClearState public: LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { } - virtual void traverse(const LLSpatialGroup::TreeNode* n) + virtual void traverse(const LLSpatialGroup::OctreeNode* n) { LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); @@ -1519,7 +1519,7 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler return false; } - virtual void traverse(const LLSpatialGroup::TreeNode* n) + virtual void traverse(const LLSpatialGroup::OctreeNode* n) { LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); diff --git a/linden/indra/newview/llstartup.cpp b/linden/indra/newview/llstartup.cpp index 08d6d3fb2..331bc301f 100644 --- a/linden/indra/newview/llstartup.cpp +++ b/linden/indra/newview/llstartup.cpp @@ -39,15 +39,16 @@ #else # include <sys/stat.h> // mkdir() #endif - -#include "audioengine.h" +#include "llpluginclassmediaowner.h" +#include "llviewermedia_streamingaudio.h" +#include "llaudioengine.h" #ifdef LL_FMOD -# include "audioengine_fmod.h" +# include "llaudioengine_fmod.h" #endif #ifdef LL_OPENAL -#include "audioengine_openal.h" +#include "llaudioengine_openal.h" #endif #include "llares.h" @@ -100,6 +101,7 @@ #include "llfloatergesture.h" #include "llfloaterhud.h" #include "llfloaterland.h" +#include "llfloaterteleporthistory.h" #include "llfloatertopobjects.h" #include "llfloatertos.h" #include "llfloaterworldmap.h" @@ -197,10 +199,6 @@ #include <Security/Security.h> #endif -#if LL_LIBXUL_ENABLED -#include "llmozlib.h" -#endif // LL_LIBXUL_ENABLED - // [RLVa:KB] #include "rlvhandler.h" // [/RLVa:KB] @@ -212,8 +210,8 @@ #include "floaterao.h" -#include "hippoGridManager.h" -#include "hippoLimits.h" +#include "hippogridmanager.h" +#include "hippolimits.h" #include "lggautocorrect.h" // @@ -683,6 +681,16 @@ bool idle_startup() delete gAudiop; gAudiop = NULL; } + + if (gAudiop) + { + // if the audio engine hasn't set up its own preferred handler for streaming audio then set up the generic streaming audio implementation which uses media plugins + if (NULL == gAudiop->getStreamingAudioImpl()) + { + LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); + } + } } } @@ -768,7 +776,7 @@ bool idle_startup() std::string msg = LLTrans::getString("LoginInitializingBrowser"); set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); display_startup(); - LLViewerMedia::initBrowser(); + // LLViewerMedia::initBrowser(); LLStartUp::setStartupState( STATE_LOGIN_SHOW ); return FALSE; @@ -933,7 +941,7 @@ bool idle_startup() ); // Overwrite default user settings with user settings - LLAppViewer::instance()->loadSettingsFromDirectory("Account"); + LLAppViewer::instance()->loadSettingsFromDirectory(AIReadAccess<settings_map_type>(gSettings), "Account"); // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation // and startup time is close enough if we don't have a real value. @@ -1073,10 +1081,11 @@ bool idle_startup() // color init must be after saved settings loaded init_colors(); - if (gSavedSettings.getBOOL("VivoxLicenseAccepted")) + if (gSavedSettings.getBOOL("VivoxLicenseAccepted") || gHippoGridManager->getConnectedGrid()->isSecondLife()) { // skipping over STATE_LOGIN_VOICE_LICENSE since we don't need it // skipping over STATE_UPDATE_CHECK because that just waits for input + // We don't do this on non-SL grids either LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); } else @@ -1819,6 +1828,10 @@ bool idle_startup() { LL_DEBUGS("AppInitStartupState") << "STATE_WORLD_INIT" << LL_ENDL; set_startup_status(0.40f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); + + // Initialize the rest of the world. + gViewerWindow->initWorldUI_postLogin(); + gDisconnected=FALSE; display_startup(); // We should have an agent id by this point. @@ -2244,6 +2257,8 @@ bool idle_startup() LLStringUtil::truncate(gWindowTitle, 255); gViewerWindow->getWindow()->setWindowTitle(gWindowTitle); } + // Inform simulator of our language preference + LLAgentLanguage::update(); // unpack thin inventory LLUserAuth::options_t options; @@ -2571,9 +2586,6 @@ bool idle_startup() // JC - 7/20/2002 gViewerWindow->sendShapeToSim(); - // Inform simulator of our language preference - LLAgentLanguage::update(); - // Ignore stipend information for now. Money history is on the web site. // if needed, show the L$ history window @@ -2757,7 +2769,9 @@ bool idle_startup() gAOInvTimer = new AOInvTimer(); } - LLFirstUse::ClientTags(); + // MoonWorld: Don't ask to download a client tag database on first use. + // See the setting ClientTagsListURL in settings.xml if you'd ever want to enable this. + //LLFirstUse::ClientTags(); // Add login location to teleport history 'teleported-into' LLVector3 agent_pos=gAgent.getPositionAgent(); @@ -3845,7 +3859,7 @@ void LLStartUp::multimediaInit() set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); display_startup(); - LLViewerMedia::initClass(); + //LLViewerMedia::initClass(); LLViewerParcelMedia::initClass(); } @@ -3854,7 +3868,7 @@ bool LLStartUp::dispatchURL() // ok, if we've gotten this far and have a startup URL if (!sSLURLCommand.empty()) { - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; LLURLDispatcher::dispatch(sSLURLCommand, web, trusted_browser); } @@ -3872,7 +3886,7 @@ bool LLStartUp::dispatchURL() || (dy*dy > SLOP*SLOP) ) { std::string url = LLURLSimString::getURL(); - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; LLURLDispatcher::dispatch(url, web, trusted_browser); } diff --git a/linden/indra/newview/llstartup.h b/linden/indra/newview/llstartup.h index 9a3c91c37..08862e63c 100644 --- a/linden/indra/newview/llstartup.h +++ b/linden/indra/newview/llstartup.h @@ -124,6 +124,9 @@ class LLStartUp static bool shouldAutoLogin() { return mShouldAutoLogin; }; static void setShouldAutoLogin(bool value) { mShouldAutoLogin = value; }; + // Returns true if startup has been successfully completed + static bool isLoggedIn() { return gStartupState == STATE_STARTED; } + private: static bool mStartedOnce; static bool mShouldAutoLogin; diff --git a/linden/indra/newview/llstatusbar.cpp b/linden/indra/newview/llstatusbar.cpp index 50be1467a..4f9864b7c 100644 --- a/linden/indra/newview/llstatusbar.cpp +++ b/linden/indra/newview/llstatusbar.cpp @@ -83,7 +83,7 @@ #include "llstring.h" #include "message.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include "viewertime.h" // @@ -109,7 +109,7 @@ const F32 ICON_TIMER_EXPIRY = 3.f; // How long the balance and health icons sho const F32 ICON_FLASH_FREQUENCY = 2.f; const S32 TEXT_HEIGHT = 18; -static void onClickParcelInfo(void*); +//static void onClickParcelInfo(void*); static void onClickBalance(void*); static void onClickBuyCurrency(void*); static void onClickHealth(void*); @@ -164,7 +164,8 @@ mSquareMetersCommitted(0) childSetAction("buycurrency", onClickBuyCurrency, this ); childSetActionTextbox("BalanceText", onClickBalance ); - childSetActionTextbox("ParcelNameText", onClickParcelInfo ); + // MoonWorld: Don't open About Land when user clicks on parcel name in the status bar. + //childSetActionTextbox("ParcelNameText", onClickParcelInfo ); // TODO: Disable buying currency when connected to non-SL grids // that don't support currency yet -- MC @@ -754,12 +755,15 @@ S32 LLStatusBar::getSquareMetersLeft() const return mSquareMetersCredit - mSquareMetersCommitted; } +// MoonWorld: this function is no longer used. +#if 0 static void onClickParcelInfo(void* data) { LLViewerParcelMgr::getInstance()->selectParcelAt(gAgent.getPositionGlobal()); LLFloaterLand::showInstance(); } +#endif static void onClickBalance(void* data) { @@ -864,7 +868,7 @@ class LLBalanceHandler : public LLCommandHandler public: // Requires "trusted" browser/URL source LLBalanceHandler() : LLCommandHandler("balance", true) { } - bool handle(const LLSD& tokens, const LLSD& query_map, LLWebBrowserCtrl* web) + bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) { if (tokens.size() == 1 && tokens[0].asString() == "request") diff --git a/linden/indra/newview/llsurface.cpp b/linden/indra/newview/llsurface.cpp index caaba056d..aaafe0da2 100644 --- a/linden/indra/newview/llsurface.cpp +++ b/linden/indra/newview/llsurface.cpp @@ -59,6 +59,7 @@ #include "llglheaders.h" #include "lldrawpoolterrain.h" #include "lldrawable.h" +#include "hippolimits.h" extern LLPipeline gPipeline; @@ -275,6 +276,7 @@ void LLSurface::createWaterTexture() *(default_texture + (i*sTextureSize/2 + j)*4 + 3) = MAX_WATER_COLOR.mV[3]; } } + mWaterTexturep = new LLViewerImage(raw, FALSE); mWaterTexturep->dontDiscard(); gGL.getTexUnit(0)->bind(mWaterTexturep.get()); @@ -295,7 +297,7 @@ void LLSurface::initTextures() // // Water texture // - if (gSavedSettings.getBOOL("RenderWater") ) + if (gSavedSettings.getBOOL("RenderWater") && gHippoLimits->mRenderWater) { createWaterTexture(); mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp); @@ -306,6 +308,29 @@ void LLSurface::initTextures() } } +//static +void LLSurface::rebuildWater() +{ + //lldebugs << "Rebuilding Water..."; + if(!mWaterObjp.isNull()) + { + //lldebugs << "Removing Water"; + //Remove the old + gObjectList.killObject(mWaterObjp); + } + + if (gSavedSettings.getBOOL("RenderWater") && gHippoLimits->mRenderWater) + { + //lldebugs << "Building Water"; + createWaterTexture(); + mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp); + gPipeline.createObject(mWaterObjp); + LLVector3d water_pos_global = from_region_handle(mRegionp->getHandle()); + water_pos_global += LLVector3d(128.0, 128.0, DEFAULT_WATER_HEIGHT); + mWaterObjp->setPositionGlobal(water_pos_global); + } + //lldebugs << "Rebuilding Water Complete"; +} void LLSurface::setOriginGlobal(const LLVector3d &origin_global) { diff --git a/linden/indra/newview/llsurface.h b/linden/indra/newview/llsurface.h index 003b2f250..c217b19a5 100644 --- a/linden/indra/newview/llsurface.h +++ b/linden/indra/newview/llsurface.h @@ -91,6 +91,8 @@ class LLSurface void disconnectNeighbor(LLSurface *neighborp); void disconnectAllNeighbors(); + void rebuildWater(); //Destroys (if nesessary) and then rebuilds (if needed) + virtual void decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL b_large_patch); virtual void updatePatchVisibilities(LLAgent &agent); diff --git a/linden/indra/newview/lltexlayer.cpp b/linden/indra/newview/lltexlayer.cpp index 5175cbb77..c8e12980d 100644 --- a/linden/indra/newview/lltexlayer.cpp +++ b/linden/indra/newview/lltexlayer.cpp @@ -61,6 +61,8 @@ using namespace LLVOAvatarDefines; +const S32 MAX_BAKE_UPLOAD_ATTEMPTS = 4; + // static S32 LLTexLayerSetBuffer::sGLByteCount = 0; @@ -98,6 +100,8 @@ LLTexLayerSetBuffer::LLTexLayerSetBuffer(LLTexLayerSet* owner, S32 width, S32 he mNeedsUpdate( TRUE ), mNeedsUpload( FALSE ), mUploadPending( FALSE ), // Not used for any logic here, just to sync sending of updates + mUploadFailCount( 0 ), + mUploadAfter( 0 ), mTexLayerSet( owner ) { LLTexLayerSetBuffer::sGLByteCount += getSize(); @@ -151,6 +155,18 @@ void LLTexLayerSetBuffer::requestUpload() { mNeedsUpload = TRUE; mUploadPending = TRUE; + mUploadAfter = 0; + } +} + +// request an upload to start delay_usec microseconds from now +void LLTexLayerSetBuffer::requestDelayedUpload(U64 delay_usec) +{ + if (!mNeedsUpload) + { + mNeedsUpload = TRUE; + mUploadPending = TRUE; + mUploadAfter = LLFrameTimer::getTotalTime() + delay_usec; } } @@ -161,6 +177,14 @@ void LLTexLayerSetBuffer::cancelUpload() mNeedsUpload = FALSE; } mUploadPending = FALSE; + mUploadAfter = 0; +} + +// do we need to upload, and do we have sufficient data to create an uploadable composite? +BOOL LLTexLayerSetBuffer::needsUploadNow() const +{ + BOOL upload = mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal() && (gAgent.mNumPendingQueries == 0); + return (upload && (LLFrameTimer::getTotalTime() > mUploadAfter)); } void LLTexLayerSetBuffer::pushProjection() @@ -187,7 +211,7 @@ void LLTexLayerSetBuffer::popProjection() BOOL LLTexLayerSetBuffer::needsRender() { LLVOAvatar* avatar = mTexLayerSet->getAvatar(); - BOOL upload_now = mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal() && gAgent.mNumPendingQueries == 0; + BOOL upload_now = needsUploadNow(); BOOL needs_update = (mNeedsUpdate || upload_now) && !avatar->mAppearanceAnimating; if (needs_update) { @@ -229,9 +253,6 @@ BOOL LLTexLayerSetBuffer::render() // Default color mask for tex layer render gGL.setColorMask(true, true); - // do we need to upload, and do we have sufficient data to create an uploadable composite? - // When do we upload the texture if gAgent.mNumPendingQueries is non-zero? - BOOL upload_now = (gAgent.mNumPendingQueries == 0 && mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal()); BOOL success = TRUE; // Composite the color data @@ -239,7 +260,7 @@ BOOL LLTexLayerSetBuffer::render() success &= mTexLayerSet->render( mOrigin.mX, mOrigin.mY, mWidth, mHeight ); gGL.flush(); - if( upload_now ) + if( needsUploadNow() ) { if (!success) { @@ -387,7 +408,8 @@ void LLTexLayerSetBuffer::readBackAndUpload() std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture"); if(!url.empty() - && !LLPipeline::sForceOldBakedUpload) // Toggle the debug setting UploadBakedTexOld to change between the new caps method and old method + && !LLPipeline::sForceOldBakedUpload // Toggle the debug setting UploadBakedTexOld to change between the new caps method and old method + && (mUploadFailCount < MAX_BAKE_UPLOAD_ATTEMPTS-1)) // allow last ditch attempt via asset store, since capabilty seems prone to transient failures. { llinfos << "Baked texture upload via capability of " << mUploadID << " to " << url << llendl; @@ -436,12 +458,14 @@ void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, void* user LLVOAvatar* avatar = gAgent.getAvatarObject(); - if (0 == result && - avatar && !avatar->isDead() && + if (avatar && !avatar->isDead() && + baked_upload_data && baked_upload_data->mAvatar == avatar && // Sanity check: only the user's avatar should be uploading textures. baked_upload_data->mLayerSet->hasComposite()) { LLTexLayerSetBuffer* layerset_buffer = baked_upload_data->mLayerSet->getComposite(); + S32 failures = layerset_buffer->mUploadFailCount; + layerset_buffer->mUploadFailCount = 0; if (layerset_buffer->mUploadID.isNull()) { @@ -469,9 +493,20 @@ void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, void* user } else { - // Avatar appearance is changing, ignore the upload results - llinfos << "Baked upload failed. Reason: " << result << llendl; - // *FIX: retry upload after n seconds, asset server could be busy + ++failures; + llinfos << "Baked upload failed (attempt " << failures << "/" << MAX_BAKE_UPLOAD_ATTEMPTS << "), "; + if (failures >= MAX_BAKE_UPLOAD_ATTEMPTS) + { + llcont << "giving up."; + } + else + { + const F32 delay = 5.f; + llcont << llformat("retrying in %.2f seconds.", delay); + layerset_buffer->mUploadFailCount = failures; + layerset_buffer->requestDelayedUpload((U64)(delay * 1000000)); + } + llcont << llendl; } } else diff --git a/linden/indra/newview/lltexlayer.h b/linden/indra/newview/lltexlayer.h index 020ba86f1..31b175ec9 100644 --- a/linden/indra/newview/lltexlayer.h +++ b/linden/indra/newview/lltexlayer.h @@ -218,6 +218,7 @@ class LLTexLayerSetBuffer : public LLDynamicTexture BOOL needsRender(); void requestUpdate(); void requestUpload(); + void requestDelayedUpload(U64 delay_usec); void cancelUpload(); BOOL uploadPending() { return mUploadPending; } BOOL render( S32 x, S32 y, S32 width, S32 height ); @@ -234,12 +235,15 @@ class LLTexLayerSetBuffer : public LLDynamicTexture private: void pushProjection(); void popProjection(); + BOOL needsUploadNow() const; private: BOOL mNeedsUpdate; BOOL mNeedsUpload; BOOL mUploadPending; LLUUID mUploadID; // Identifys the current upload process (null if none). Used to avoid overlaps (eg, when the user rapidly makes two changes outside of Face Edit) + S32 mUploadFailCount; + U64 mUploadAfter; // delay upload until after this time (in microseconds) LLTexLayerSet* mTexLayerSet; static S32 sGLByteCount; diff --git a/linden/indra/newview/lltexturecache.cpp b/linden/indra/newview/lltexturecache.cpp index a1a9a3985..2b032a586 100644 --- a/linden/indra/newview/lltexturecache.cpp +++ b/linden/indra/newview/lltexturecache.cpp @@ -736,9 +736,6 @@ void LLTextureCacheWorker::endWork(S32 param, bool aborted) LLTextureCache::LLTextureCache(bool threaded) : LLWorkerThread("TextureCache", threaded), - mWorkersMutex(NULL), - mHeaderMutex(NULL), - mListMutex(NULL), mHeaderAPRFile(NULL), mReadOnly(FALSE), mTexturesSizeTotal(0), @@ -1541,7 +1538,7 @@ bool LLTextureCache::readComplete(handle_t handle, bool abort) } } - unlockWorkers(); + unlockWorkers(); if (delete_worker) worker->scheduleDelete(); diff --git a/linden/indra/newview/lltexturecache.h b/linden/indra/newview/lltexturecache.h index c859b9aee..56b4c4f51 100644 --- a/linden/indra/newview/lltexturecache.h +++ b/linden/indra/newview/lltexturecache.h @@ -139,9 +139,6 @@ class LLTextureCache : public LLWorkerThread std::string getTextureFileName(const LLUUID& id); void addCompleted(Responder* responder, bool success); -protected: - //void setFileAPRPool(apr_pool_t* pool) { mFileAPRPool = pool ; } - private: void setDirNames(ELLPath location); void readHeaderCache(); diff --git a/linden/indra/newview/lltexturefetch.cpp b/linden/indra/newview/lltexturefetch.cpp index b5ad4351c..072af2595 100644 --- a/linden/indra/newview/lltexturefetch.cpp +++ b/linden/indra/newview/lltexturefetch.cpp @@ -157,7 +157,7 @@ class LLTextureFetchWorker : public LLWorkerClass void callbackHttpGet(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer, - bool last_block, bool success); + bool partial, bool unsatisfiable, bool success); void callbackCacheRead(bool success, LLImageFormatted* image, S32 imagesize, BOOL islocal); void callbackCacheWrite(bool success); @@ -317,13 +317,14 @@ class HTTPGetResponder : public LLCurl::Responder mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow); } - lldebugs << "HTTP COMPLETE: " << mID << llendl; + LL_DEBUGS("TextureFetch") << "HTTP COMPLETE: " << mID << " with status: " << status << LL_ENDL; mFetcher->lockQueue(); LLTextureFetchWorker* worker = mFetcher->getWorker(mID); if (worker) { bool success = false; bool partial = false; + bool unsatisfiable = false; if (200 <= status && status < 300) { success = true; @@ -332,18 +333,19 @@ class HTTPGetResponder : public LLCurl::Responder partial = true; } } - else + else if (status == HTTP_REQUESTED_RANGE_NOT_SATISFIABLE) { - worker->setGetStatus(status, reason); -// llwarns << status << ": " << reason << llendl; + LL_DEBUGS("TextureFetch") << "Request was an unsatisfiable range: mRequestedSize=" << mRequestedSize << " mOffset=" << mOffset << " for: " << mID << LL_ENDL; + unsatisfiable = true; } + if (!success) { worker->setGetStatus(status, reason); // llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl; } mFetcher->removeFromHTTPQueue(mID); - worker->callbackHttpGet(channels, buffer, partial, success); + worker->callbackHttpGet(channels, buffer, partial, unsatisfiable, success); } else { @@ -426,7 +428,6 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, mRetryAttempt(0), mActiveCount(0), mGetStatus(0), - mWorkMutex(NULL), mFirstPacket(0), mLastPacket(-1), mTotalPackets(0), @@ -870,6 +871,16 @@ bool LLTextureFetchWorker::doWork(S32 param) return false; } } + + // *TODO: remove this hack when not needed anymore + S32 buggy_range_fudge = 0; + if (LLTextureFetch::hasBuggyHTTPRange()) + { + buggy_range_fudge = 1; + resetFormattedData(); // discard any previous data we had + cur_size = 0 ; + } + mRequestedSize = mDesiredSize; mRequestedDiscard = mDesiredDiscard; mRequestedSize -= cur_size; @@ -883,10 +894,11 @@ bool LLTextureFetchWorker::doWork(S32 param) mLoaded = FALSE; mGetStatus = 0; mGetReason.clear(); - lldebugs << "HTTP GET: " << mID << " Offset: " << offset + LL_DEBUGS("TextureFetch") << "HTTP GET: " << mID << " Offset: " << offset << " Bytes: " << mRequestedSize + << " Range: " << offset << "-" << offset+mRequestedSize-1+buggy_range_fudge << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << max_bandwidth - << llendl; + << LL_ENDL; setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); mState = WAIT_HTTP_REQ; @@ -894,7 +906,7 @@ bool LLTextureFetchWorker::doWork(S32 param) // Will call callbackHttpGet when curl request completes std::vector<std::string> headers; headers.push_back("Accept: image/x-j2c"); - res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize, + res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize + buggy_range_fudge, new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset)); } if (!res) @@ -1301,7 +1313,9 @@ bool LLTextureFetchWorker::processSimulatorPackets() void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer, - bool last_block, bool success) + bool partial, + bool unsatisfiable, + bool success) { LLMutexLock lock(&mWorkMutex); @@ -1316,56 +1330,91 @@ void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, llwarns << "Duplicate callback for " << mID.asString() << llendl; return; // ignore duplicate callback } + + S32 data_size = 0; if (success) { // get length of stream: - S32 data_size = buffer->countAfter(channels.in(), NULL); + data_size = buffer->countAfter(channels.in(), NULL); gImageList.sTextureBits += data_size * 8; // Approximate - does not include header bits - //llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl; + LL_DEBUGS("TextureFetch") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << " mRequestedSize: " << mRequestedSize << LL_ENDL; + if (data_size > 0) { - // *TODO: set the formatted image data here directly to avoid the copy - mBuffer = new U8[data_size]; - buffer->readAfter(channels.in(), NULL, mBuffer, data_size); - mBufferSize += data_size; - if (data_size < mRequestedSize && - (mRequestedDiscard == 0 || mRequestedSize >= MAX_IMAGE_DATA_SIZE) ) + bool clean_data = false; + bool done = false; + if (!partial) { - // We requested whole image (by discard or by size,) so assume we got it - mHaveAllData = TRUE; + // we got the whole image in one go + done = true; + clean_data = true; + } + else if (data_size < mRequestedSize) + { + // we have the whole image + done = true; + } + else if (data_size == mRequestedSize) + { + if (mRequestedDiscard <= 0) + { + done = true; + } + else + { + // this is the normal case where we get the data we requested, + // but still need to request more data. + } } else if (data_size > mRequestedSize) { // *TODO: This shouldn't be happening any more llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl; - mHaveAllData = TRUE; + done = true; + clean_data = true; llassert_always(mDecodeHandle == 0); - mFormattedImage = NULL; // discard any previous data we had - mBufferSize = data_size; } - mRequestedSize = data_size; - } - else - { - // We requested data but received none (and no error), - if (mFormattedImage.notNull() && mFormattedImage->getDataSize() > 0) + + if (clean_data) { - // but have earlier data, so presumably we have it all. - mRequestedSize = 0; - mHaveAllData = TRUE; + resetFormattedData(); // discard any previous data we had + llassert(mBufferSize == 0); } - else + if (done) { - mRequestedSize = -1; // treat this fetch as if it failed. + mHaveAllData = TRUE; + mRequestedDiscard = 0; } + + // *TODO: set the formatted image data here directly to avoid the copy + mBuffer = new U8[data_size]; + buffer->readAfter(channels.in(), NULL, mBuffer, data_size); + mBufferSize += data_size; + mRequestedSize = data_size; } } else { mRequestedSize = -1; // error } + + if ((success && (data_size == 0)) || unsatisfiable) + { + if (mFormattedImage.notNull() && mFormattedImage->getDataSize() > 0) + { + // we already have some data, so we'll assume we have it all + mRequestedSize = 0; + mRequestedDiscard = 0; + mHaveAllData = TRUE; + } + else + { + mRequestedSize = -1; // treat this fetch as if it failed. + } + } + mLoaded = TRUE; setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); } @@ -1490,8 +1539,6 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mDebugPause(FALSE), mPacketCount(0), mBadPacketCount(0), - mQueueMutex(getAPRPool()), - mNetworkQueueMutex(getAPRPool()), mTextureCache(cache), mImageDecodeThread(imagedecodethread), mTextureBandwidth(0), @@ -2220,3 +2267,44 @@ void LLTextureFetch::dump() } } +// This tries to detect if the sim has this bug: +// http://opensimulator.org/mantis/view.php?id=5081 +// +// *TODO: This is a *HACK and may not work if the grid is heterogenous. +// Remove it once OpenSim versions in the wild are > 0.7.0.2! +#include "hippogridmanager.h" +#include <boost/regex.hpp> +//static +bool LLTextureFetch::hasBuggyHTTPRange() +{ + static std::string s_version; + static bool buggy = false; + if ((s_version != gLastVersionChannel) && !gLastVersionChannel.empty()) + { + s_version = gLastVersionChannel; + buggy = false; + if (gHippoGridManager->getConnectedGrid()->getPlatform() == HippoGridInfo::PLATFORM_OPENSIM) + { + std::string ver_string; + try + { + const boost::regex re(".*OpenSim.*?([0-9.]+).+"); + ver_string = regex_replace(s_version, re, "\\1", boost::match_default); + } + catch(std::runtime_error) + { + ver_string = "0.0"; + } + LLStringUtil::replaceChar(ver_string, '.', '0'); + ver_string = "0." + ver_string; + F64 version = atof(ver_string.c_str()); + // we look for "0.6.8" < version < "0.7.0.3" + if ((version > 0.00608) && (version < 0.0070003)) + { + buggy = true; + llwarns << "Setting buggy http ranges mode for current sim, because we're on " << s_version << llendl; + } + } + } + return buggy; +} diff --git a/linden/indra/newview/lltexturefetch.h b/linden/indra/newview/lltexturefetch.h index 6c6bb52eb..5fa2d1c17 100644 --- a/linden/indra/newview/lltexturefetch.h +++ b/linden/indra/newview/lltexturefetch.h @@ -86,6 +86,8 @@ class LLTextureFetch : public LLWorkerThread LLTextureInfo* getTextureInfo() { return &mTextureInfo; } + static bool hasBuggyHTTPRange(); // *TODO: remove this *HACK once buggy OpenSim versions are gone + protected: void addToNetworkQueue(LLTextureFetchWorker* worker); void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel); diff --git a/linden/indra/newview/lltoolcomp.cpp b/linden/indra/newview/lltoolcomp.cpp index b6090bc98..7bf99f050 100644 --- a/linden/indra/newview/lltoolcomp.cpp +++ b/linden/indra/newview/lltoolcomp.cpp @@ -55,6 +55,7 @@ #include "llagent.h" #include "llfloatertools.h" #include "llviewercontrol.h" +#include "qtoolalign.h" const S32 BUTTON_HEIGHT = 16; const S32 BUTTON_WIDTH_SMALL = 32; @@ -278,7 +279,12 @@ BOOL LLToolCompTranslate::handleMouseUp(S32 x, S32 y, MASK mask) LLTool* LLToolCompTranslate::getOverrideTool(MASK mask) { - if (mask == MASK_CONTROL) + if (gKeyboard->getKeyDown('A') && + ((mask & MASK_CONTROL) || (mask == (MASK_CONTROL | MASK_SHIFT)))) + { + return QToolAlign::getInstance(); + } + else if (mask == MASK_CONTROL) { return LLToolCompRotate::getInstance(); } @@ -397,7 +403,12 @@ BOOL LLToolCompScale::handleMouseUp(S32 x, S32 y, MASK mask) LLTool* LLToolCompScale::getOverrideTool(MASK mask) { - if (mask == MASK_CONTROL) + if (gKeyboard->getKeyDown('A') && + ((mask & MASK_CONTROL) || (mask == (MASK_CONTROL | MASK_SHIFT)))) + { + return QToolAlign::getInstance(); + } + else if (mask == MASK_CONTROL) { return LLToolCompRotate::getInstance(); } @@ -597,7 +608,12 @@ BOOL LLToolCompRotate::handleMouseUp(S32 x, S32 y, MASK mask) LLTool* LLToolCompRotate::getOverrideTool(MASK mask) { - if (mask == (MASK_CONTROL | MASK_SHIFT)) + if (gKeyboard->getKeyDown('A') && + ((mask & MASK_CONTROL) || (mask == (MASK_CONTROL | MASK_SHIFT)))) + { + return QToolAlign::getInstance(); + } + else if (mask == (MASK_CONTROL | MASK_SHIFT)) { return LLToolCompScale::getInstance(); } @@ -766,10 +782,6 @@ void LLToolCompGun::onMouseCaptureLost() return; } mCur->onMouseCaptureLost(); - - // JC - I don't know if this is necessary. Maybe we could lose capture - // if someone ALT-Tab's out when in mouselook. - setCurrentTool( (LLTool*) mGun ); } void LLToolCompGun::handleSelect() diff --git a/linden/indra/newview/lltoolcomp.h b/linden/indra/newview/lltoolcomp.h index b24ba25d5..81ed0ba8e 100644 --- a/linden/indra/newview/lltoolcomp.h +++ b/linden/indra/newview/lltoolcomp.h @@ -229,6 +229,7 @@ class LLToolCompGun : public LLToolComposite, public LLSingleton<LLToolCompGun> virtual void onMouseCaptureLost(); virtual void handleSelect(); virtual void handleDeselect(); + virtual LLTool* getOverrideTool(MASK mask) { return NULL; } protected: LLToolGun* mGun; diff --git a/linden/indra/newview/lltooldraganddrop.cpp b/linden/indra/newview/lltooldraganddrop.cpp index 2bc6e3ef2..18c49178d 100644 --- a/linden/indra/newview/lltooldraganddrop.cpp +++ b/linden/indra/newview/lltooldraganddrop.cpp @@ -75,6 +75,7 @@ // [RLVa:KB] #include "rlvhandler.h" // [/RLVa:KB] +#include "hippolimits.h" // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES // or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a @@ -1679,8 +1680,10 @@ void LLToolDragAndDrop::giveInventoryCategory(const LLUUID& to_agent, LLNotifications::instance().add("IncompleteInventory"); return; } + count = items.count() + cats.count(); - if(count > MAX_ITEMS) + if(count > gHippoLimits->getMaxInventoryItemsTransfer() && + gHippoLimits->getMaxInventoryItemsTransfer() != -1) //MAX_ITEMS) { LLNotifications::instance().add("TooManyItems"); return; @@ -1776,8 +1779,9 @@ void LLToolDragAndDrop::commitGiveInventoryCategory(const LLUUID& to_agent, // MTUBYTES or 18 * count < 1200 => count < 1200/18 => // 66. I've cut it down a bit from there to give some pad. S32 count = items.count() + cats.count(); - if(count > MAX_ITEMS) - { + if(count > gHippoLimits->getMaxInventoryItemsTransfer() && + gHippoLimits->getMaxInventoryItemsTransfer() != -1) //MAX_ITEMS) + { LLNotifications::instance().add("TooManyItems"); return; } diff --git a/linden/indra/newview/lltoolgrab.cpp b/linden/indra/newview/lltoolgrab.cpp index 9b6d6f76b..10b043113 100644 --- a/linden/indra/newview/lltoolgrab.cpp +++ b/linden/indra/newview/lltoolgrab.cpp @@ -64,7 +64,7 @@ #include "llvoavatar.h" #include "llworld.h" -#include "hippoLimits.h" +#include "hippolimits.h" // [RLVa:KB] #include "rlvhandler.h" diff --git a/linden/indra/newview/lltoolgun.cpp b/linden/indra/newview/lltoolgun.cpp index d21fd4964..f7af01870 100644 --- a/linden/indra/newview/lltoolgun.cpp +++ b/linden/indra/newview/lltoolgun.cpp @@ -49,7 +49,8 @@ #include "lltoolgrab.h" LLToolGun::LLToolGun( LLToolComposite* composite ) -: LLTool( std::string("gun"), composite ) +: LLTool( std::string("gun"), composite ), + mIsSelected(FALSE) { } @@ -58,6 +59,7 @@ void LLToolGun::handleSelect() gViewerWindow->hideCursor(); gViewerWindow->moveCursorToCenter(); gViewerWindow->mWindow->setMouseClipping(TRUE); + mIsSelected = TRUE; } void LLToolGun::handleDeselect() @@ -65,6 +67,7 @@ void LLToolGun::handleDeselect() gViewerWindow->moveCursorToCenter(); gViewerWindow->showCursor(); gViewerWindow->mWindow->setMouseClipping(FALSE); + mIsSelected = FALSE; } BOOL LLToolGun::handleMouseDown(S32 x, S32 y, MASK mask) @@ -77,7 +80,7 @@ BOOL LLToolGun::handleMouseDown(S32 x, S32 y, MASK mask) BOOL LLToolGun::handleHover(S32 x, S32 y, MASK mask) { - if( gAgent.cameraMouselook() ) + if( gAgent.cameraMouselook() && mIsSelected ) { const F32 NOMINAL_MOUSE_SENSITIVITY = 0.0025f; diff --git a/linden/indra/newview/lltoolgun.h b/linden/indra/newview/lltoolgun.h index 4e945d796..4644e686b 100644 --- a/linden/indra/newview/lltoolgun.h +++ b/linden/indra/newview/lltoolgun.h @@ -52,6 +52,8 @@ class LLToolGun : public LLTool virtual LLTool* getOverrideTool(MASK mask) { return NULL; } virtual BOOL clipMouseWhenDown() { return FALSE; } +private: + BOOL mIsSelected; }; #endif diff --git a/linden/indra/newview/lltoolmgr.cpp b/linden/indra/newview/lltoolmgr.cpp index 3a776d12b..82043746e 100644 --- a/linden/indra/newview/lltoolmgr.cpp +++ b/linden/indra/newview/lltoolmgr.cpp @@ -281,22 +281,20 @@ void LLToolMgr::clearTransientTool() } -// The "gun tool", used for handling mouselook, captures the mouse and -// locks it within the window. When the app loses focus we need to -// release this locking. void LLToolMgr::onAppFocusLost() { - mSavedTool = mBaseTool; - mBaseTool = gToolNull; + if (mSelectedTool) + { + mSelectedTool->handleDeselect(); + } updateToolStatus(); } void LLToolMgr::onAppFocusGained() { - if (mSavedTool) + if (mSelectedTool) { - mBaseTool = mSavedTool; - mSavedTool = NULL; + mSelectedTool->handleSelect(); } updateToolStatus(); } diff --git a/linden/indra/newview/lltoolmorph.cpp b/linden/indra/newview/lltoolmorph.cpp index 75e19645a..6e09efa7d 100644 --- a/linden/indra/newview/lltoolmorph.cpp +++ b/linden/indra/newview/lltoolmorph.cpp @@ -37,7 +37,7 @@ #include "llrender.h" // Library includes -#include "audioengine.h" +#include "llaudioengine.h" #include "llviewercontrol.h" #include "llfontgl.h" #include "sound_ids.h" diff --git a/linden/indra/newview/lltoolpie.cpp b/linden/indra/newview/lltoolpie.cpp index 02ad008df..46f122f3d 100644 --- a/linden/indra/newview/lltoolpie.cpp +++ b/linden/indra/newview/lltoolpie.cpp @@ -36,11 +36,11 @@ #include "indra_constants.h" #include "llclickaction.h" -#include "llmediabase.h" // for status codes #include "llparcel.h" #include "llagent.h" #include "llviewercontrol.h" +#include "llfocusmgr.h" #include "llfirstuse.h" #include "llfloateravatarinfo.h" #include "llfloaterland.h" @@ -63,6 +63,7 @@ #include "llviewerparcelmgr.h" #include "llviewerwindow.h" #include "llviewermedia.h" +#include "llviewermediafocus.h" #include "llvoavatar.h" #include "llworld.h" #include "llui.h" @@ -76,13 +77,15 @@ extern void handle_buy(void*); extern BOOL gDebugClicks; +static bool handle_media_click(const LLPickInfo& info); +static bool handle_media_hover(const LLPickInfo& info); static void handle_click_action_play(); static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp); static ECursorType cursor_from_parcel_media(U8 click_action); LLToolPie::LLToolPie() -: LLTool(std::string("Select")), +: LLTool(std::string("Pie")), mPieMouseButtonDown( FALSE ), mGrabMouseButtonDown( FALSE ), mMouseOutsideSlop( FALSE ), @@ -114,6 +117,10 @@ BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask) return FALSE; } +BOOL LLToolPie::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks); +} // static void LLToolPie::rightMouseCallback(const LLPickInfo& pick_info) { @@ -147,6 +154,7 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) } } + gFocusMgr.setKeyboardFocus(NULL); return LLTool::handleMouseDown(x, y, mask); } @@ -165,9 +173,11 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) parent = object->getRootEdit(); } + BOOL touchable = (object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch()); + // If it's a left-click, and we have a special action, do it. if (useClickAction(always_show, mask, object, parent)) { @@ -199,6 +209,8 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) if ((gAgent.getAvatarObject() != NULL) && (!gAgent.getAvatarObject()->mIsSitting) && !gSavedSettings.getBOOL("BlockClickSit")) // agent not already sitting { handle_sit_or_stand(); + // put focus in world when sitting on an object + gFocusMgr.setKeyboardFocus(NULL); return TRUE; } // else nothing (fall through to touch) @@ -251,6 +263,14 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) } } + if (!always_show && handle_media_click(mPick)) + { + return FALSE; + } + + // put focus back "in world" + gFocusMgr.setKeyboardFocus(NULL); + // Switch to grab tool if physical or triggerable if (object && !object->isAvatar() && @@ -330,6 +350,8 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) // Spawn pie menu if (mPick.mPickType == LLPickInfo::PICK_LAND) { + if (gPieLand) // MoonWorld: gPieLand is gone! + { LLParcelSelectionHandle selection = LLViewerParcelMgr::getInstance()->selectParcelAt( mPick.mPosGlobal ); gMenuHolder->setParcelSelection(selection); gPieLand->show(x, y, mPieMouseButtonDown); @@ -339,15 +361,16 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) effectp->setPositionGlobal(mPick.mPosGlobal); effectp->setColor(LLColor4U(gAgent.getEffectColor())); effectp->setDuration(0.25f); + } } else if (object && is_self) { -// if(gPieSelf) -// { + if(gPieSelf) + { //either at very early startup stage or at late quitting stage, //this event is ignored. gPieSelf->show(x, y, mPieMouseButtonDown); -// } + } } @@ -437,6 +460,8 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) ) { // [/RLVa:KB] + if (gPieObject) // MoonWorld: Allow the object pie menu to be gone. + { gPieObject->show(x, y, mPieMouseButtonDown); // VEFFECT: ShowPie object @@ -446,6 +471,7 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) effectp->setPositionGlobal(mPick.mPosGlobal); effectp->setColor(LLColor4U(gAgent.getEffectColor())); effectp->setDuration(0.25f); + } // [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Added: RLVa-0.2.0f } else @@ -624,62 +650,71 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) mMouseOutsideSlop = TRUE; } */ - + + LLViewerObject *object = NULL; LLViewerObject *parent = NULL; - if (gHoverView) - { -// object = gViewerWindow->getHoverPick().getObject(); + // [RLVa:KB] - Alternate: Snowglobe-1.2.4 | Checked: 2010-01-02 (RLVa-1.1.0l) | Modified: RLVa-1.1.0l - // Block all special click action cursors when: - // - @fartouch=n restricted and the object is out of range - // - @interact=n restricted and the object isn't a HUD attachment - const LLPickInfo& pick = gViewerWindow->getHoverPick(); - object = pick.getObject(); - if ( (object) && (rlv_handler_t::isEnabled()) && - ( ((gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH))) && (!gRlvHandler.canTouch(object, pick.mObjectOffset)) || - ((gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) && (!object->isHUDAttachment())) ) ) - { - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - return TRUE; - } -// [/RLVa:KB] +// object = gViewerWindow->getHoverPick().getObject(); + // Block all special click action cursors when: + // - @fartouch=n restricted and the object is out of range + // - @interact=n restricted and the object isn't a HUD attachment + const LLPickInfo& pick = gViewerWindow->getHoverPick(); + object = pick.getObject(); + if ( (object) && (rlv_handler_t::isEnabled()) && + ( ((gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH))) && (!gRlvHandler.canTouch(object, pick.mObjectOffset)) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) && (!object->isHUDAttachment())) ) ) + { + gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + return TRUE; } +// [/RLVa:KB] if (object) { parent = object->getRootEdit(); - } - if (object && useClickAction(FALSE, mask, object, parent)) - { - ECursorType cursor = cursor_from_object(object); - gViewerWindow->getWindow()->setCursor(cursor); - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; - } + if (object && useClickAction(FALSE, mask, object, parent)) + { + ECursorType cursor = cursor_from_object(object); + gViewerWindow->getWindow()->setCursor(cursor); + } + else if (handle_media_hover(gViewerWindow->getHoverPick())) + { + // cursor set by media object + } // [RLVa:KB] - Checked: 2010-01-02 (RLVa-1.1.0l) | Added: RLVa-1.1.0l - else if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object)) ) - { - // Block showing the "grab" or "touch" cursor if we can't touch the object (@fartouch=n is handled above) - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - } + else if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object)) ) + { + // Block showing the "grab" or "touch" cursor if we can't touch the object (@fartouch=n is handled above) + gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + } // [/RLVa:KB] - else if ((object && !object->isAvatar() && object->usePhysics()) - || (parent && !parent->isAvatar() && parent->usePhysics())) - { - gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLGRAB); - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; - } - else if ( (object && object->flagHandleTouch()) - || (parent && parent->flagHandleTouch())) - { - gViewerWindow->getWindow()->setCursor(UI_CURSOR_HAND); - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; + else if ((object && !object->isAvatar() && object->usePhysics()) + || (parent && !parent->isAvatar() && parent->usePhysics())) + { + gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLGRAB); + } + else if ( (object && object->flagHandleTouch()) + || (parent && parent->flagHandleTouch())) + { + gViewerWindow->getWindow()->setCursor(UI_CURSOR_HAND); + } + else + { + gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + } } else { gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; + // We need to clear media hover flag + if (LLViewerMediaFocus::getInstance()->getMouseOverFlag()) + { + LLViewerMediaFocus::getInstance()->setMouseOverFlag(false); + } + } return TRUE; @@ -861,14 +896,14 @@ static void handle_click_action_play() LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (!parcel) return; - LLMediaBase::EStatus status = LLViewerParcelMedia::getStatus(); + LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getStatus(); switch(status) { - case LLMediaBase::STATUS_STARTED: + case LLViewerMediaImpl::MEDIA_PLAYING: LLViewerParcelMedia::pause(); break; - case LLMediaBase::STATUS_PAUSED: + case LLViewerMediaImpl::MEDIA_PAUSED: LLViewerParcelMedia::start(); break; @@ -878,6 +913,111 @@ static void handle_click_action_play() } } +static bool handle_media_click(const LLPickInfo& pick) +{ + //FIXME: how do we handle object in different parcel than us? + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + LLPointer<LLViewerObject> objectp = pick.getObject(); + + + if (!parcel || + objectp.isNull() || + pick.mObjectFace < 0 || + pick.mObjectFace >= objectp->getNumTEs()) + { + LLSelectMgr::getInstance()->deselect(); + LLViewerMediaFocus::getInstance()->clearFocus(); + + return false; + } + + + + // HACK: This is directly referencing an impl name. BAD! + // This can be removed when we have a truly generic media browser that only + // builds an impl based on the type of url it is passed. + + // is media playing on this face? + const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); + + viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(tep->getID()); + if (tep + && media_impl.notNull() + && media_impl->hasMedia() + && gSavedSettings.getBOOL("MediaOnAPrimUI")) + { + LLObjectSelectionHandle selection = LLViewerMediaFocus::getInstance()->getSelection(); + if (! selection->contains(pick.getObject(), pick.mObjectFace)) + { + LLViewerMediaFocus::getInstance()->setFocusFace(TRUE, pick.getObject(), pick.mObjectFace, media_impl); + } + else + { + media_impl->mouseDown(pick.mXYCoords.mX, pick.mXYCoords.mY); + media_impl->mouseCapture(); // the mouse-up will happen when capture is lost + } + + return true; + } + + LLSelectMgr::getInstance()->deselect(); + LLViewerMediaFocus::getInstance()->clearFocus(); + + return false; +} + +static bool handle_media_hover(const LLPickInfo& pick) +{ + //FIXME: how do we handle object in different parcel than us? + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (!parcel) return false; + + LLPointer<LLViewerObject> objectp = pick.getObject(); + + // Early out cases. Must clear mouse over media focus flag + // did not hit an object or did not hit a valid face + if ( objectp.isNull() || + pick.mObjectFace < 0 || + pick.mObjectFace >= objectp->getNumTEs() ) + { + LLViewerMediaFocus::getInstance()->setMouseOverFlag(false); + return false; + } + + + // HACK: This is directly referencing an impl name. BAD! + // This can be removed when we have a truly generic media browser that only + // builds an impl based on the type of url it is passed. + + // is media playing on this face? + const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); + viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(tep->getID()); + if (tep + && media_impl.notNull() + && media_impl->hasMedia() + && gSavedSettings.getBOOL("MediaOnAPrimUI")) + { + if(LLViewerMediaFocus::getInstance()->getFocus()) + { + media_impl->mouseMove(pick.mXYCoords.mX, pick.mXYCoords.mY); + } + + // Set mouse over flag if unset + if (! LLViewerMediaFocus::getInstance()->getMouseOverFlag()) + { + LLSelectMgr::getInstance()->setHoverObject(objectp, pick.mObjectFace); + LLViewerMediaFocus::getInstance()->setMouseOverFlag(true, media_impl); + LLViewerMediaFocus::getInstance()->setPickInfo(pick); + } + + return true; + } + LLViewerMediaFocus::getInstance()->setMouseOverFlag(false); + + return false; +} + + static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp) { //FIXME: how do we handle object in different parcel than us? @@ -892,7 +1032,7 @@ static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp) if( face < 0 || face >= objectp->getNumTEs() ) return; // is media playing on this face? - if (!LLViewerMedia::isActiveMediaTexture(objectp->getTE(face)->getID())) + if (LLViewerMedia::getMediaImplFromTextureID(objectp->getTE(face)->getID()) != NULL) { handle_click_action_play(); return; @@ -910,10 +1050,7 @@ static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp) // This can be removed when we have a truly generic media browser that only // builds an impl based on the type of url it is passed. - if( LLMediaManager::getInstance()->supportsMediaType( "LLMediaImplLLMozLib", media_scheme, media_type ) ) - { - LLWeb::loadURL(media_url); - } + LLWeb::loadURL(media_url); } static ECursorType cursor_from_parcel_media(U8 click_action) @@ -931,19 +1068,12 @@ static ECursorType cursor_from_parcel_media(U8 click_action) std::string media_type = std::string ( parcel->getMediaType() ); LLStringUtil::trim(media_url); - // Get the scheme, see if that is handled as well. - LLURI uri(media_url); - std::string media_scheme = uri.scheme() != "" ? uri.scheme() : "http"; - - if( LLMediaManager::getInstance()->supportsMediaType( "LLMediaImplLLMozLib", media_scheme, media_type ) ) - { - open_cursor = UI_CURSOR_TOOLMEDIAOPEN; - } + open_cursor = UI_CURSOR_TOOLMEDIAOPEN; - LLMediaBase::EStatus status = LLViewerParcelMedia::getStatus(); + LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getStatus(); switch(status) { - case LLMediaBase::STATUS_STARTED: + case LLViewerMediaImpl::MEDIA_PLAYING: return click_action == CLICK_ACTION_PLAY ? UI_CURSOR_TOOLPAUSE : open_cursor; default: return UI_CURSOR_TOOLPLAY; diff --git a/linden/indra/newview/lltoolpie.h b/linden/indra/newview/lltoolpie.h index 113fba771..001886f72 100644 --- a/linden/indra/newview/lltoolpie.h +++ b/linden/indra/newview/lltoolpie.h @@ -51,6 +51,7 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie> virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); virtual void render(); diff --git a/linden/indra/newview/lltoolplacer.cpp b/linden/indra/newview/lltoolplacer.cpp index 477dbcac8..52053f557 100644 --- a/linden/indra/newview/lltoolplacer.cpp +++ b/linden/indra/newview/lltoolplacer.cpp @@ -59,7 +59,7 @@ #include "llvolumemessage.h" #include "llhudmanager.h" #include "llagent.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llhudeffecttrail.h" #include "llviewerobjectlist.h" #include "llviewercamera.h" diff --git a/linden/indra/newview/llurldispatcher.cpp b/linden/indra/newview/llurldispatcher.cpp index f9b6b39a1..1144c5827 100644 --- a/linden/indra/newview/llurldispatcher.cpp +++ b/linden/indra/newview/llurldispatcher.cpp @@ -39,7 +39,7 @@ #include "llfloaterurldisplay.h" #include "llfloaterdirectory.h" #include "llfloaterworldmap.h" -#include "llfloaterhtmlhelp.h" +#include "llfloatermediabrowser.h" #include "llpanellogin.h" #include "llstartup.h" // gStartupState #include "llurlsimstring.h" @@ -65,7 +65,7 @@ class LLURLDispatcherImpl static bool isSLURLCommand(const std::string& url); static bool dispatch(const std::string& url, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); // returns true if handled or explicitly blocked. @@ -74,7 +74,7 @@ class LLURLDispatcherImpl private: static bool dispatchCore(const std::string& url, bool right_mouse, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); // handles both left and right click @@ -84,7 +84,7 @@ class LLURLDispatcherImpl static bool dispatchApp(const std::string& url, bool right_mouse, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); // Handles secondlife:///app/agent/<agent_id>/about and similar // by showing panel in Search floater. @@ -138,7 +138,7 @@ bool LLURLDispatcherImpl::isSLURLCommand(const std::string& url) // static bool LLURLDispatcherImpl::dispatchCore(const std::string& url, bool right_mouse, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { if (url.empty()) return false; @@ -158,7 +158,7 @@ bool LLURLDispatcherImpl::dispatchCore(const std::string& url, // static bool LLURLDispatcherImpl::dispatch(const std::string& url, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { llinfos << "url: " << url << llendl; @@ -171,7 +171,7 @@ bool LLURLDispatcherImpl::dispatchRightClick(const std::string& url) { llinfos << "url: " << url << llendl; const bool right_click = true; - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; return dispatchCore(url, right_click, web, trusted_browser); } @@ -192,7 +192,7 @@ bool LLURLDispatcherImpl::dispatchHelp(const std::string& url, bool right_mouse) // static bool LLURLDispatcherImpl::dispatchApp(const std::string& url, bool right_mouse, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { if (!isSLURL(url)) @@ -386,7 +386,7 @@ class LLTeleportHandler : public LLCommandHandler LLTeleportHandler() : LLCommandHandler("teleport", true) { } bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { // construct a "normal" SLURL, resolve the region to // a global position, and teleport to it @@ -426,7 +426,7 @@ bool LLURLDispatcher::isSLURLCommand(const std::string& url) // static bool LLURLDispatcher::dispatch(const std::string& url, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { return LLURLDispatcherImpl::dispatch(url, web, trusted_browser); @@ -448,7 +448,7 @@ bool LLURLDispatcher::dispatchFromTextEditor(const std::string& url) // click on it. // *TODO: Make this trust model more refined. JC const bool trusted_browser = true; - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; return LLURLDispatcherImpl::dispatch(url, web, trusted_browser); } diff --git a/linden/indra/newview/llurldispatcher.h b/linden/indra/newview/llurldispatcher.h index a4f6866a0..c947e5e37 100644 --- a/linden/indra/newview/llurldispatcher.h +++ b/linden/indra/newview/llurldispatcher.h @@ -32,7 +32,7 @@ #ifndef LLURLDISPATCHER_H #define LLURLDISPATCHER_H -class LLWebBrowserCtrl; +class LLMediaCtrl; class LLURLDispatcher @@ -45,7 +45,7 @@ class LLURLDispatcher // Is this a special secondlife://app/ URL? static bool dispatch(const std::string& url, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); // At startup time and on clicks in internal web browsers, // teleport, open map, or run requested command. @@ -54,7 +54,7 @@ class LLURLDispatcher // secondlife:///app/agent/3d6181b0-6a4b-97ef-18d8-722652995cf1/show // sl://app/foo/bar // @param web - // Pointer to LLWebBrowserCtrl sending URL, can be NULL + // Pointer to LLMediaCtrl sending URL, can be NULL // @param trusted_browser // True if coming inside the app AND from a brower instance // that navigates to trusted (Linden Lab) pages. diff --git a/linden/indra/newview/llurlhistory.cpp b/linden/indra/newview/llurlhistory.cpp index fbd14bcaa..b187f3b22 100644 --- a/linden/indra/newview/llurlhistory.cpp +++ b/linden/indra/newview/llurlhistory.cpp @@ -74,7 +74,7 @@ bool LLURLHistory::loadFile(const std::string& filename) // static bool LLURLHistory::saveFile(const std::string& filename) { - std::string temp_str = gDirUtilp->getLindenUserDir(); + std::string temp_str = gDirUtilp->getLindenUserDir(true); if( temp_str.empty() ) { llwarns << "Can't save " << filename diff --git a/linden/indra/newview/llviewerassetstorage.h b/linden/indra/newview/llviewerassetstorage.h index 15c11c702..512b590a1 100644 --- a/linden/indra/newview/llviewerassetstorage.h +++ b/linden/indra/newview/llviewerassetstorage.h @@ -47,6 +47,7 @@ class LLViewerAssetStorage : public LLAssetStorage LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs); + using LLAssetStorage::storeAssetData; virtual void storeAssetData( const LLTransactionID& tid, LLAssetType::EType atype, diff --git a/linden/indra/newview/llvieweraudio.cpp b/linden/indra/newview/llvieweraudio.cpp index 672836d86..91e7ce566 100644 --- a/linden/indra/newview/llvieweraudio.cpp +++ b/linden/indra/newview/llvieweraudio.cpp @@ -32,7 +32,7 @@ #include "llviewerprecompiledheaders.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llagent.h" #include "llappviewer.h" #include "llvieweraudio.h" @@ -134,7 +134,6 @@ void audio_update_volume(bool force_update) gAudiop->setMasterGain ( master_volume ); gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler")); - gAudiop->setDistanceFactor(gSavedSettings.getF32("AudioLevelDistance")); gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff")); if(wind_muted == false) diff --git a/linden/indra/newview/llviewercamera.cpp b/linden/indra/newview/llviewercamera.cpp index dade65f1a..16f6e57f7 100644 --- a/linden/indra/newview/llviewercamera.cpp +++ b/linden/indra/newview/llviewercamera.cpp @@ -743,7 +743,9 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts) LLVolume* volume = volumep->getVolume(); if (!volume) { - return FALSE; + BOOL inside = pointInFrustum(volumep->getRenderPosition()); + + return (inside > 0); } LLVOVolume* vo_volume = (LLVOVolume*) volumep; diff --git a/linden/indra/newview/llviewercontrol.cpp b/linden/indra/newview/llviewercontrol.cpp index 88ea904c4..703e62a69 100644 --- a/linden/indra/newview/llviewercontrol.cpp +++ b/linden/indra/newview/llviewercontrol.cpp @@ -38,7 +38,7 @@ #include "indra_constants.h" // For Listeners -#include "audioengine.h" +#include "llaudioengine.h" #include "llagent.h" #include "llconsole.h" #include "lldrawpoolterrain.h" @@ -69,17 +69,15 @@ #include "llvosurfacepatch.h" #include "llvowlsky.h" #include "llrender.h" -#include "llmediamanager.h" #include "llslider.h" #include "llfloaterchat.h" - +#include "aithreadsafe.h" #ifdef TOGGLE_HACKED_GODLIKE_VIEWER BOOL gHackGodmode = FALSE; #endif - -std::map<std::string, LLControlGroup*> gSettings; +AITHREADSAFE(settings_map_type, gSettings,); LLControlGroup gSavedSettings; // saved at end of session LLControlGroup gSavedPerAccountSettings; // saved at end of session LLControlGroup gColors; // read-only @@ -498,21 +496,6 @@ bool handleTranslateChatPrefsChanged(const LLSD& newvalue) return true; } -bool handleMediaDebugLevelChanged(const LLSD& newvalue) -{ - LLMediaManager *mgr = LLMediaManager::getInstance(); - if (mgr) - { - LLMediaBase *impl = - mgr->createSourceFromMimeType("http", "audio/mpeg"); - - if (impl) - { - impl->setDebugLevel( (LLMediaBase::EDebugLevel)newvalue.asInteger() ); - } - } - return true; -} bool handleSliderScrollWheelMultiplierChanged(const LLSD& newvalue) { @@ -661,7 +644,6 @@ void settings_setup_listeners() gSavedSettings.getControl("VoiceOutputAudioDevice")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); gSavedSettings.getControl("AudioLevelMic")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); gSavedSettings.getControl("LipSyncEnabled")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); - gSavedSettings.getControl("MediaDebugLevel")->getSignal()->connect(boost::bind(&handleMediaDebugLevelChanged, _1)); gSavedSettings.getControl("SliderScrollWheelMultiplier")->getSignal()->connect(boost::bind(&handleSliderScrollWheelMultiplierChanged, _1)); gSavedSettings.getControl("TranslateChat")->getSignal()->connect(boost::bind(&handleTranslateChatPrefsChanged, _1)); } diff --git a/linden/indra/newview/llviewercontrol.h b/linden/indra/newview/llviewercontrol.h index d0dc80cb9..780940fc2 100644 --- a/linden/indra/newview/llviewercontrol.h +++ b/linden/indra/newview/llviewercontrol.h @@ -35,6 +35,7 @@ #include <map> #include "llcontrol.h" +#include "aithreadsafe.h" // Enabled this definition to compile a 'hacked' viewer that // allows a hacked godmode to be toggled on and off. @@ -47,7 +48,8 @@ extern BOOL gHackGodmode; //setting variables are declared in this function void settings_setup_listeners(); -extern std::map<std::string, LLControlGroup*> gSettings; +typedef std::map<std::string, LLControlGroup*> settings_map_type; +extern AIThreadSafe<settings_map_type> gSettings; // for the graphics settings void create_graphics_group(LLControlGroup& group); diff --git a/linden/indra/newview/llviewerdisplay.cpp b/linden/indra/newview/llviewerdisplay.cpp index 78940cc30..59a87d5f3 100644 --- a/linden/indra/newview/llviewerdisplay.cpp +++ b/linden/indra/newview/llviewerdisplay.cpp @@ -82,6 +82,7 @@ #include "llwlparammanager.h" #include "llwaterparammanager.h" #include "llpostprocess.h" +#include "hippolimits.h" // [RLVa:KB] #include "rlvhandler.h" @@ -181,6 +182,12 @@ void display_update_camera() { final_far *= 0.5f; } + if(gAgent.mLockedDrawDistance) + { + //Reset the draw distance and do not update with the new val + final_far = LLViewerCamera::getInstance()->getFar(); + gAgent.mDrawDistance = final_far; + } LLViewerCamera::getInstance()->setFar(final_far); gViewerWindow->setup3DRender(); @@ -305,13 +312,19 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // Update GL Texture statistics (used for discard logic?) // + LLAppViewer::instance()->pingMainloopTimeout("Display:TextureStats"); gFrameStats.start(LLFrameStats::UPDATE_TEX_STATS); stop_glerror(); LLImageGL::updateStats(gFrameTimeSeconds); - LLVOAvatar::sRenderName = gSavedSettings.getS32("RenderName"); + S32 RenderName = gSavedSettings.getS32("RenderName"); + + if(RenderName > gHippoLimits->mRenderName)//The most restricted gets set here + RenderName = gHippoLimits->mRenderName; + + LLVOAvatar::sRenderName = RenderName; LLVOAvatar::sRenderGroupTitles = !gSavedSettings.getBOOL("RenderHideGroupTitleAll"); gPipeline.mBackfaceCull = TRUE; @@ -835,6 +848,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) //} LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE; + + //Check for RenderWater + if (!gSavedSettings.getBOOL("RenderWater") || !gHippoLimits->mRenderWater) + LLPipeline::sUnderWaterRender = FALSE; + LLPipeline::updateRenderDeferred(); stop_glerror(); diff --git a/linden/indra/newview/llviewergesture.cpp b/linden/indra/newview/llviewergesture.cpp index 01b3c5814..7799c9947 100644 --- a/linden/indra/newview/llviewergesture.cpp +++ b/linden/indra/newview/llviewergesture.cpp @@ -34,7 +34,7 @@ #include "llviewergesture.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "lldir.h" #include "llviewerinventory.h" #include "sound_ids.h" // for testing diff --git a/linden/indra/newview/llviewerimagelist.cpp b/linden/indra/newview/llviewerimagelist.cpp index 869c9d7b5..039896f8f 100644 --- a/linden/indra/newview/llviewerimagelist.cpp +++ b/linden/indra/newview/llviewerimagelist.cpp @@ -597,7 +597,7 @@ void LLViewerImageList::updateImages(F32 max_time) llpushcallstacks ; if (!gNoRender && !gGLManager.mIsDisabled) { - LLViewerMedia::updateImagesMediaStreams(); + LLViewerMedia::updateMedia(); } llpushcallstacks ; updateImagesUpdateStats(); diff --git a/linden/indra/newview/llviewerinventory.cpp b/linden/indra/newview/llviewerinventory.cpp index 33113f17f..0e06353ab 100644 --- a/linden/indra/newview/llviewerinventory.cpp +++ b/linden/indra/newview/llviewerinventory.cpp @@ -268,7 +268,7 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const msg->addU32Fast(_PREHASH_Flags, mFlags); mSaleInfo.packMessage(msg); msg->addStringFast(_PREHASH_Name, mName); - msg->addStringFast(_PREHASH_Description, mDescription); + msg->addStringFast(_PREHASH_Description, mDescription); msg->addS32Fast(_PREHASH_CreationDate, mCreationDate); U32 crc = getCRC32(); msg->addU32Fast(_PREHASH_CRC, crc); diff --git a/linden/indra/newview/llviewerkeyboard.cpp b/linden/indra/newview/llviewerkeyboard.cpp index 15c814829..6dd7fb506 100644 --- a/linden/indra/newview/llviewerkeyboard.cpp +++ b/linden/indra/newview/llviewerkeyboard.cpp @@ -506,7 +506,7 @@ void start_chat( EKeystate s ) void start_gesture( EKeystate s ) { if (KEYSTATE_UP == s && - !(gFocusMgr.getKeyboardFocus() && gFocusMgr.getKeyboardFocus()->acceptsTextInput())) + !(gFocusMgr.getKeyboardFocus() && dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus())->acceptsTextInput())) { if (gChatBar->getCurrentChat().empty()) { diff --git a/linden/indra/newview/llviewermedia.cpp b/linden/indra/newview/llviewermedia.cpp index 6bcf8cea6..5c01b2543 100644 --- a/linden/indra/newview/llviewermedia.cpp +++ b/linden/indra/newview/llviewermedia.cpp @@ -33,687 +33,1206 @@ #include "llviewerprecompiledheaders.h" #include "llviewermedia.h" - +#include "llviewermediafocus.h" +#include "llhoverview.h" #include "llmimetypes.h" #include "llviewercontrol.h" #include "llviewerimage.h" #include "llviewerwindow.h" #include "llviewerimagelist.h" -#include "viewerversion.h" +//#include "viewerversion.h" + +#include "llpluginclassmedia.h" #include "llevent.h" // LLSimpleListener -#include "llmediamanager.h" #include "lluuid.h" +#include "llkeyboard.h" -#include <boost/bind.hpp> // for SkinFolder listener -#include <boost/signal.hpp> +// Merov: Temporary definitions while porting the new viewer media code to Snowglobe +const int LEFT_BUTTON = 0; +const int RIGHT_BUTTON = 1; -// Implementation functions not exported into header file -class LLViewerMediaImpl - : public LLMediaObserver +// Move this to its own file. + +LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() { - public: - LLViewerMediaImpl() - : mMediaSource( NULL ), - mMovieImageID(), - mMovieImageHasMips(false) - { } - - void destroyMediaSource(); - - void play(const std::string& media_url, - const std::string& mime_type, - const LLUUID& placeholder_texture_id, - S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop); - - void stop(); - void pause(); - void start(); - void seek(F32 time); - void setVolume(F32 volume); - LLMediaBase::EStatus getStatus(); - - /*virtual*/ void onMediaSizeChange(const EventType& event_in); - /*virtual*/ void onMediaContentsChange(const EventType& event_in); - - void updateMovieImage(const LLUUID& image_id, BOOL active); - void updateImagesMediaStreams(); - LLUUID getMediaTextureID(); - - // Internally set our desired browser user agent string, including - // the Second Life version and skin name. Used because we can - // switch skins without restarting the app. - static void updateBrowserUserAgent(); - - // Callback for when the SkinCurrent control is changed to - // switch the user agent string to indicate the new skin. - static bool handleSkinCurrentChanged(const LLSD& newvalue); + observerListType::iterator iter = mObservers.begin(); - public: + while( iter != mObservers.end() ) + { + LLViewerMediaObserver *self = *iter; + iter++; + remObserver(self); + } +} - // a single media url with some data and an impl. - LLMediaBase* mMediaSource; - LLUUID mMovieImageID; - bool mMovieImageHasMips; - std::string mMediaURL; - std::string mMimeType; - private: - void initializePlaceholderImage(LLViewerImage *placeholder_image, LLMediaBase *media_source); -}; +/////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer ) +{ + if ( ! observer ) + return false; -static LLViewerMediaImpl sViewerMediaImpl; + if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() ) + return false; -////////////////////////////////////////////////////////////////////////////////////////// + mObservers.push_back( observer ); + observer->mEmitters.push_back( this ); -void LLViewerMediaImpl::destroyMediaSource() + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer ) +{ + if ( ! observer ) + return false; + + mObservers.remove( observer ); + observer->mEmitters.remove(this); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLPluginClassMediaOwner::EMediaEvent event ) { - LLMediaManager* mgr = LLMediaManager::getInstance(); - if ( mMediaSource ) + observerListType::iterator iter = mObservers.begin(); + + while( iter != mObservers.end() ) { - bool was_playing = LLViewerMedia::isMediaPlaying(); - mMediaSource->remObserver(this); - mgr->destroySource( mMediaSource ); + LLViewerMediaObserver *self = *iter; + ++iter; + self->handleMediaEvent( media, event ); + } +} - // Restore the texture - updateMovieImage(LLUUID::null, was_playing); +// Move this to its own file. +LLViewerMediaObserver::~LLViewerMediaObserver() +{ + std::list<LLViewerMediaEventEmitter *>::iterator iter = mEmitters.begin(); + while( iter != mEmitters.end() ) + { + LLViewerMediaEventEmitter *self = *iter; + iter++; + self->remObserver( this ); } - mMediaSource = NULL; } -void LLViewerMediaImpl::play(const std::string& media_url, - const std::string& mime_type, - const LLUUID& placeholder_texture_id, - S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop) + +// Move this to its own file. +// helper class that tries to download a URL from a web site and calls a method +// on the Panel Land Media and to discover the MIME type +class LLMimeDiscoveryResponder : public LLHTTPClient::Responder { - // first stop any previously playing media - stop(); +LOG_CLASS(LLMimeDiscoveryResponder); +public: + LLMimeDiscoveryResponder( viewer_media_t media_impl) + : mMediaImpl(media_impl), + mInitialized(false) + {} + - // Save this first, as init/load below may fire events - mMovieImageID = placeholder_texture_id; - // If the mime_type passed in is different than the cached one, and - // Auto-discovery is turned OFF, replace the cached mime_type with the new one. - if(mime_type != mMimeType && - ! gSavedSettings.getBOOL("AutoMimeDiscovery")) + virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + std::string media_type = content["content-type"].asString(); + std::string::size_type idx1 = media_type.find_first_of(";"); + std::string mime_type = media_type.substr(0, idx1); + completeAny(status, mime_type); + } + + virtual void error( U32 status, const std::string& reason ) { - mMimeType = mime_type; + // completeAny(status, "none/none"); } - LLURI url(media_url); - std::string scheme = url.scheme() != "" ? url.scheme() : "http"; - LLMediaManager* mgr = LLMediaManager::getInstance(); - mMediaSource = mgr->createSourceFromMimeType(scheme, mMimeType ); - if ( !mMediaSource ) + void completeAny(U32 status, const std::string& mime_type) { - if (mMimeType != "none/none") + if(!mInitialized && ! mime_type.empty()) { - llwarns << "media source create failed " << media_url - << " type " << mMimeType - << llendl; + if (mMediaImpl->initializeMedia(mime_type)) + { + mInitialized = true; + mMediaImpl->play(); + } } - return; } - // Store the URL and Mime Type - mMediaURL = media_url; + public: + viewer_media_t mMediaImpl; + bool mInitialized; +}; +typedef std::list<LLViewerMediaImpl*> impl_list; +static impl_list sViewerMediaImplList; + +////////////////////////////////////////////////////////////////////////////////////////// +// LLViewerMedia - if ((media_width != 0) && (media_height != 0)) +////////////////////////////////////////////////////////////////////////////////////////// +// static +viewer_media_t LLViewerMedia::newMediaImpl(const std::string& media_url, + const LLUUID& texture_id, + S32 media_width, S32 media_height, U8 media_auto_scale, + U8 media_loop, + std::string mime_type) +{ + LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id); + if(media_impl == NULL || texture_id.isNull()) { - mMediaSource->setRequestedMediaSize(media_width, media_height); + // Create the media impl + media_impl = new LLViewerMediaImpl(media_url, texture_id, media_width, media_height, media_auto_scale, media_loop, mime_type); + sViewerMediaImplList.push_back(media_impl); } - - mMediaSource->setLooping(media_loop); - mMediaSource->setAutoScaled(media_auto_scale); - mMediaSource->addObserver( this ); - mMediaSource->navigateTo( media_url ); - mMediaSource->addCommand(LLMediaBase::COMMAND_START); + else + { + media_impl->stop(); + media_impl->mTextureId = texture_id; + media_impl->mMediaURL = media_url; + media_impl->mMediaWidth = media_width; + media_impl->mMediaHeight = media_height; + media_impl->mMediaAutoScale = media_auto_scale; + media_impl->mMediaLoop = media_loop; + if(! media_url.empty()) + media_impl->navigateTo(media_url, mime_type, true); + } + return media_impl; } -void LLViewerMediaImpl::stop() +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::removeMedia(LLViewerMediaImpl* media) { - destroyMediaSource(); + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + if(media == *iter) + { + sViewerMediaImplList.erase(iter); + return; + } + } } -void LLViewerMediaImpl::pause() +////////////////////////////////////////////////////////////////////////////////////////// +// static +LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id) { - if(mMediaSource) + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) { - mMediaSource->addCommand(LLMediaBase::COMMAND_PAUSE); + LLViewerMediaImpl* media_impl = *iter; + if(media_impl->getMediaTextureID() == texture_id) + { + return media_impl; + } } + return NULL; } -void LLViewerMediaImpl::start() +////////////////////////////////////////////////////////////////////////////////////////// +// static +std::string LLViewerMedia::getCurrentUserAgent() { - if(mMediaSource) + // Don't include version, channel, or skin -- MC + + // Don't use user-visible string to avoid + // punctuation and strange characters. + //std::string skin_name = gSavedSettings.getString("SkinCurrent"); + + // Just in case we need to check browser differences in A/B test + // builds. + //std::string channel = gSavedSettings.getString("VersionChannelName"); + + // append our magic version number string to the browser user agent id + // See the HTTP 1.0 and 1.1 specifications for allowed formats: + // http://www.ietf.org/rfc/rfc1945.txt section 10.15 + // http://www.ietf.org/rfc/rfc2068.txt section 3.8 + // This was also helpful: + // http://www.mozilla.org/build/revised-user-agent-strings.html + std::ostringstream codec; + codec << "SecondLife/"; + codec << "C64 Basic V2"; + //codec << ViewerVersion::getImpMajorVersion() << "." << ViewerVersion::getImpMinorVersion() << "." << ViewerVersion::getImpPatchVersion() << " " << ViewerVersion::getImpTestVersion(); + //codec << " (" << channel << "; " << skin_name << " skin)"; +// llinfos << codec.str() << llendl; + + return codec.str(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::updateBrowserUserAgent() +{ + std::string user_agent = getCurrentUserAgent(); + + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) { - mMediaSource->addCommand(LLMediaBase::COMMAND_START); + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser()) + { + pimpl->mMediaSource->setBrowserUserAgent(user_agent); + } } + } -void LLViewerMediaImpl::seek(F32 time) +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/) { - if(mMediaSource) + // gSavedSettings is already updated when this function is called. + updateBrowserUserAgent(); + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id) +{ + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) { - mMediaSource->seek(time); + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->getMediaTextureID() == texture_id) + { + return true; + } } + return false; } -void LLViewerMediaImpl::setVolume(F32 volume) +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setVolume(F32 volume) { - if(mMediaSource) + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) { - mMediaSource->setVolume( volume); + LLViewerMediaImpl* pimpl = *iter; + pimpl->setVolume(volume); } } -LLMediaBase::EStatus LLViewerMediaImpl::getStatus() +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::updateMedia() { - if (mMediaSource) + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) { - return mMediaSource->getStatus(); + LLViewerMediaImpl* pimpl = *iter; + pimpl->update(); } - else +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::cleanupClass() +{ + // This is no longer necessary, since the list is no longer smart pointers. +#if 0 + while(!sViewerMediaImplList.empty()) { - return LLMediaBase::STATUS_UNKNOWN; + sViewerMediaImplList.pop_back(); } +#endif } ////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMediaImpl::updateMovieImage(const LLUUID& uuid, BOOL active) +// LLViewerMediaImpl +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaImpl::LLViewerMediaImpl(const std::string& media_url, + const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop, + const std::string& mime_type) +: + mMediaSource( NULL ), + mMovieImageHasMips(false), + mTextureId(texture_id), + mMediaWidth(media_width), + mMediaHeight(media_height), + mMediaAutoScale(media_auto_scale), + mMediaLoop(media_loop), + mMediaURL(media_url), + mMimeType(mime_type), + mNeedsNewTexture(true), + mSuspendUpdates(false), + mVisible(true) +{ + createMediaSource(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaImpl::~LLViewerMediaImpl() { - // IF the media image hasn't changed, do nothing - if (mMovieImageID == uuid) + if( gEditMenuHandler == this ) { - return; + gEditMenuHandler = NULL; } - // If we have changed media uuid, restore the old one - if (!mMovieImageID.isNull()) + + destroyMediaSource(); + LLViewerMedia::removeMedia(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) +{ + if((mMediaSource == NULL) || (mMimeType != mime_type)) { - LLViewerImage* oldImage = LLViewerImage::getImage( mMovieImageID ); - if (oldImage) + if(! initializePlugin(mime_type)) { - oldImage->reinit(mMovieImageHasMips); - oldImage->mIsMediaTexture = FALSE; + LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << mime_type << LL_ENDL; + LLSD args; + args["MIME_TYPE"] = mime_type; + LLNotifications::instance().add("NoPlugin", args); + + return false; } - mMovieImageID.setNull(); } - // If the movie is playing, set the new media image - if (active && !uuid.isNull()) + + // play(); + return (mMediaSource != NULL); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::createMediaSource() +{ + if(! mMediaURL.empty()) { - LLViewerImage* viewerImage = LLViewerImage::getImage( uuid ); - if( viewerImage ) - { - mMovieImageID = uuid; - // Can't use mipmaps for movies because they don't update the full image - mMovieImageHasMips = viewerImage->getUseMipMaps(); - viewerImage->reinit(FALSE); - viewerImage->mIsMediaTexture = TRUE; - } + navigateTo(mMediaURL, mMimeType, true); + } + else if(! mMimeType.empty()) + { + initializeMedia(mMimeType); } + } +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::destroyMediaSource() +{ + mNeedsNewTexture = true; + if(! mMediaSource) + { + return; + } + // Restore the texture + updateMovieImage(LLUUID::null, false); + delete mMediaSource; + mMediaSource = NULL; +} ////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMediaImpl::updateImagesMediaStreams() +void LLViewerMediaImpl::setMediaType(const std::string& media_type) { - LLMediaManager::updateClass(); + mMimeType = media_type; } -void LLViewerMediaImpl::initializePlaceholderImage(LLViewerImage *placeholder_image, LLMediaBase *media_source) +////////////////////////////////////////////////////////////////////////////////////////// +/*static*/ +LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height) { - int media_width = media_source->getMediaWidth(); - int media_height = media_source->getMediaHeight(); - //int media_rowspan = media_source->getMediaRowSpan(); + std::string plugin_basename = LLMIMETypes::implType(media_type); - // if width & height are invalid, don't bother doing anything - if ( media_width < 1 || media_height < 1 ) - return; + if(plugin_basename.empty()) + { + LL_WARNS("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL; + } + else + { + std::string launcher_name = gDirUtilp->getLLPluginLauncher(); + std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename); + std::string user_data_path = gDirUtilp->getOSUserAppDir(); + user_data_path += gDirUtilp->getDirDelimiter(); + + // Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.) + // If the linden username returned is blank, that can only mean we are + // at the login page displaying login Web page or Web browser test via Develop menu. + // In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this + // is what we always used before this change) + std::string linden_user_dir = gDirUtilp->getLindenUserDir(true); + if ( ! linden_user_dir.empty() ) + { + // gDirUtilp->getLindenUserDir() is whole path, not just Linden name + user_data_path = linden_user_dir; + user_data_path += gDirUtilp->getDirDelimiter(); + } - llinfos << "initializing media placeholder" << llendl; - llinfos << "movie image id " << mMovieImageID << llendl; + // See if the plugin executable exists + llstat s; + if(LLFile::stat(launcher_name, &s)) + { + LL_WARNS("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; + } + else if(LLFile::stat(plugin_name, &s)) + { + LL_WARNS("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; + } + else + { + LLPluginClassMedia* media_source = new LLPluginClassMedia(owner); + media_source->setSize(default_width, default_height); + media_source->setUserDataPath(user_data_path); + media_source->setLanguageCode(LLUI::getLanguage()); - int texture_width = LLMediaManager::textureWidthFromMediaWidth( media_width ); - int texture_height = LLMediaManager::textureHeightFromMediaHeight( media_height ); - int texture_depth = media_source->getMediaDepth(); + // collect 'cookies enabled' setting from prefs and send to embedded browser + bool cookies_enabled = gSavedSettings.getBOOL( "BrowserCookiesEnabled" ); + media_source->enable_cookies( cookies_enabled ); - // MEDIAOPT: check to see if size actually changed before doing work - placeholder_image->destroyGLTexture(); - // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? - placeholder_image->reinit(FALSE); // probably not needed + // collect 'plugins enabled' setting from prefs and send to embedded browser + bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" ); + media_source->setPluginsEnabled( plugins_enabled ); - // MEDIAOPT: seems insane that we actually have to make an imageraw then - // immediately discard it - LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth); - raw->clear(0x0f, 0x0f, 0x0f, 0xff); - int discard_level = 0; + // collect 'javascript enabled' setting from prefs and send to embedded browser + bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" ); + media_source->setJavascriptEnabled( javascript_enabled ); - // ask media source for correct GL image format constants - placeholder_image->setExplicitFormat(media_source->getTextureFormatInternal(), - media_source->getTextureFormatPrimary(), - media_source->getTextureFormatType()); + if (media_source->init(launcher_name, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))) + { + return media_source; + } + else + { + LL_WARNS("Media") << "Failed to init plugin. Destroying." << LL_ENDL; + delete media_source; + } + } + } - placeholder_image->createGLTexture(discard_level, raw); + LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL; + LLSD args; + args["MIME_TYPE"] = media_type; + LLNotifications::instance().add("NoPlugin", args); - // placeholder_image->setExplicitFormat() - placeholder_image->setUseMipMaps(FALSE); + return NULL; +} - // MEDIAOPT: set this dynamically on play/stop - placeholder_image->mIsMediaTexture = true; -} +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) +{ + if(mMediaSource) + { + // Save the previous media source's last set size before destroying it. + mMediaWidth = mMediaSource->getSetWidth(); + mMediaHeight = mMediaSource->getSetHeight(); + } + + // Always delete the old media impl first. + destroyMediaSource(); + + // and unconditionally set the mime type + mMimeType = media_type; + LLPluginClassMedia* media_source = newSourceFromMediaType(media_type, this, mMediaWidth, mMediaHeight); + + if (media_source) + { + media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout")); + media_source->setLoop(mMediaLoop); + media_source->setAutoScale(mMediaAutoScale); + media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent()); + + mMediaSource = media_source; + return true; + } + return false; +} -// virtual -void LLViewerMediaImpl::onMediaContentsChange(const EventType& event_in) +void LLViewerMediaImpl::setSize(int width, int height) +{ + mMediaWidth = width; + mMediaHeight = height; + if(mMediaSource) + { + mMediaSource->setSize(width, height); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::play() { - LLMediaBase* media_source = event_in.getSubject(); - LLViewerImage* placeholder_image = gImageList.getImage( mMovieImageID ); - if ((placeholder_image) && (placeholder_image->getHasGLTexture())) + // first stop any previously playing media + // stop(); + + // mMediaSource->addObserver( this ); + if(mMediaSource == NULL) { - if (placeholder_image->getUseMipMaps()) + if(!initializePlugin(mMimeType)) { - // bad image! NO MIPMAPS! - initializePlaceholderImage(placeholder_image, media_source); + // Plugin failed initialization... should assert or something + return; } + } + + // updateMovieImage(mTextureId, true); - U8* data = media_source->getMediaData(); - S32 x_pos = 0; - S32 y_pos = 0; - S32 width = media_source->getMediaWidth(); - S32 height = media_source->getMediaHeight(); - S32 data_width = media_source->getMediaDataWidth(); - S32 data_height = media_source->getMediaDataHeight(); - placeholder_image->setSubImage(data, data_width, data_height, - x_pos, y_pos, width, height); + mMediaSource->loadURI( mMediaURL ); + if(/*mMediaSource->pluginSupportsMediaTime()*/ true) + { + start(); } } +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::stop() +{ + if(mMediaSource) + { + mMediaSource->stop(); + // destroyMediaSource(); + } +} -// virtual -void LLViewerMediaImpl::onMediaSizeChange(const EventType& event_in) +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::pause() { - LLMediaBase* media_source = event_in.getSubject(); - LLViewerImage* placeholder_image = gImageList.getImage( mMovieImageID ); - if (placeholder_image) + if(mMediaSource) { - initializePlaceholderImage(placeholder_image, media_source); + mMediaSource->pause(); } - else +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::start() +{ + if(mMediaSource) { - llinfos << "no placeholder image" << llendl; + mMediaSource->start(); } } +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::seek(F32 time) +{ + if(mMediaSource) + { + mMediaSource->seek(time); + } +} - // Get the image we're using +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setVolume(F32 volume) +{ + if(mMediaSource) + { + mMediaSource->setVolume(volume); + } +} - /* - // update media stream if required - LLMediaEngine* media_engine = LLMediaEngine::getInstance(); - if (media_engine) +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::focus(bool focus) +{ + if (mMediaSource) { - if ( media_engine->update() ) - { - LLUUID media_uuid = media_engine->getImageUUID(); - updateMovieImage(media_uuid, TRUE); - if (!media_uuid.isNull()) - { - LLViewerImage* viewerImage = getImage( media_uuid ); - if( viewerImage ) - { - LLMediaBase* renderer = media_engine->getMediaRenderer(); - if ((renderer->getTextureWidth() != viewerImage->getWidth()) || - (renderer->getTextureHeight() != viewerImage->getHeight()) || - (renderer->getTextureDepth() != viewerImage->getComponents()) || - (viewerImage->getHasGLTexture() == FALSE)) - { - // destroy existing GL image - viewerImage->destroyGLTexture(); - - // set new size - viewerImage->setSize( renderer->getTextureWidth(), - renderer->getTextureHeight(), - renderer->getTextureDepth() ); - - LLPointer<LLImageRaw> raw = new LLImageRaw(renderer->getTextureWidth(), - renderer->getTextureHeight(), - renderer->getTextureDepth()); - raw->clear(0x7f,0x7f,0x7f,0xff); - viewerImage->createGLTexture(0, raw); - } - - // Set the explicit format the instance wants - viewerImage->setExplicitFormat(renderer->getTextureFormatInternal(), - renderer->getTextureFormatPrimary(), - renderer->getTextureFormatType(), - renderer->getTextureFormatSwapBytes()); - // This should be redundant, but just in case: - viewerImage->setUseMipMaps(FALSE); - - LLImageRaw* rawImage = media_engine->getImageRaw(); - if ( rawImage ) - { - viewerImage->setSubImage(rawImage, 0, 0, - renderer->getMediaWidth(), - renderer->getMediaHeight()); - } - } - else - { - llwarns << "MediaEngine update unable to get viewer image for GL texture" << llendl; - } - } - } - else + // call focus just for the hell of it, even though this apopears to be a nop + mMediaSource->focus(focus); + if (focus) { - LLUUID media_uuid = media_engine->getImageUUID(); - updateMovieImage(media_uuid, FALSE); + // spoof a mouse click to *actually* pass focus + // Don't do this anymore -- it actually clicks through now. +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); } } - */ - +} -LLUUID LLViewerMediaImpl::getMediaTextureID() +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDown(S32 x, S32 y) { - return mMovieImageID; + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, LEFT_BUTTON, x, y, 0); + } } -// static -void LLViewerMediaImpl::updateBrowserUserAgent() +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseUp(S32 x, S32 y) { - // Don't use user-visible string to avoid - // punctuation and strange characters. - std::string skin_name = gSavedSettings.getString("SkinCurrent"); - - // Just in case we need to check browser differences in A/B test - // builds. - std::string channel = gSavedSettings.getString("VersionChannelName"); - - // append our magic version number string to the browser user agent id - // See the HTTP 1.0 and 1.1 specifications for allowed formats: - // http://www.ietf.org/rfc/rfc1945.txt section 10.15 - // http://www.ietf.org/rfc/rfc2068.txt section 3.8 - // This was also helpful: - // http://www.mozilla.org/build/revised-user-agent-strings.html - std::ostringstream codec; - codec << "SecondLife/"; - codec << ViewerVersion::getLLMajorVersion() << "." << ViewerVersion::getLLMinorVersion() << "." << ViewerVersion::getLLPatchVersion() << "." << ViewerVersion::getLLBuildVersion(); - codec << " (" << channel << "; " << skin_name << " skin)"; - llinfos << codec.str() << llendl; - LLMediaManager::setBrowserUserAgent( codec.str() ); + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, x, y, 0); + } } -// static -bool LLViewerMediaImpl::handleSkinCurrentChanged(const LLSD& /*newvalue*/) +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseMove(S32 x, S32 y) { - // gSavedSettings is already updated when this function is called. - updateBrowserUserAgent(); - return true; + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, LEFT_BUTTON, x, y, 0); + } } ////////////////////////////////////////////////////////////////////////////////////////// -// Wrapper class +void LLViewerMediaImpl::mouseLeftDoubleClick(S32 x, S32 y) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, LEFT_BUTTON, x, y, 0); + } +} + ////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::onMouseCaptureLost() +{ + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, mLastMouseX, mLastMouseY, 0); + } +} +////////////////////////////////////////////////////////////////////////////////////////// +BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) +{ + // NOTE: this is called when the mouse is released when we have capture. + // Due to the way mouse coordinates are mapped to the object, we can't use the x and y coordinates that come in with the event. + + if(hasMouseCapture()) + { + // Release the mouse -- this will also send a mouseup to the media + gFocusMgr.setMouseCapture( FALSE ); + } + return TRUE; +} ////////////////////////////////////////////////////////////////////////////////////////// -// The viewer takes a long time to load the start screen. Part of the problem -// is media initialization -- in particular, QuickTime loads many DLLs and -// hits the disk heavily. So we initialize only the browser component before -// the login screen, then do the rest later when we have a progress bar. JC -// static -void LLViewerMedia::initBrowser() +void LLViewerMediaImpl::navigateHome() { - LLMediaManagerData* init_data = new LLMediaManagerData; - buildMediaManagerData( init_data ); - LLMediaManager::initBrowser( init_data ); - delete init_data; - - // We use a custom user agent with viewer version and skin name. - LLViewerMediaImpl::updateBrowserUserAgent(); + if(mMediaSource) + { + mMediaSource->loadURI( mHomeURL ); + } } ////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::initClass() +void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type) { - // *TODO: This looks like a memory leak to me. JC - LLMediaManagerData* init_data = new LLMediaManagerData; - buildMediaManagerData( init_data ); - LLMediaManager::initClass( init_data ); - delete init_data; + if(rediscover_type) + { - LLMediaManager* mm = LLMediaManager::getInstance(); - LLMIMETypes::mime_info_map_t::const_iterator it; - for (it = LLMIMETypes::sMap.begin(); it != LLMIMETypes::sMap.end(); ++it) + LLURI uri(url); + std::string scheme = uri.scheme(); + + if(scheme.empty() || "http" == scheme || "https" == scheme) + { + LLHTTPClient::getHeaderOnly( url, new LLMimeDiscoveryResponder(this)); + } + else if("data" == scheme || "file" == scheme || "about" == scheme) + { + // FIXME: figure out how to really discover the type for these schemes + // We use "data" internally for a text/html url for loading the login screen + if(initializeMedia("text/html")) + { + mMediaSource->loadURI( url ); + } + } + else + { + // This catches 'rtsp://' urls + if(initializeMedia(scheme)) + { + mMediaSource->loadURI( url ); + } + } + } + else if (mMediaSource) { - const std::string& mime_type = it->first; - const LLMIMETypes::LLMIMEInfo& info = it->second; - mm->addMimeTypeImplNameMap( mime_type, info.mImpl ); + mMediaSource->loadURI( url ); } - - LLMediaBase *impl = mm->createSourceFromMimeType("http", "audio/mpeg"); - if (impl) + else if(initializeMedia(mime_type) && mMediaSource) + { + mMediaSource->loadURI( url ); + } + else { - U32 level = gSavedSettings.getU32("MediaDebugLevel"); - impl->setDebugLevel( (LLMediaBase::EDebugLevel)level ); + LL_WARNS("Media") << "Couldn't navigate to: " << url << " as there is no media type for: " << mime_type << LL_ENDL; + return; } + mMediaURL = url; + } ////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::buildMediaManagerData( LLMediaManagerData* init_data ) -{ -// std::string executable_dir = std::string( arg0 ).substr( 0, std::string( arg0 ).find_last_of("\\/") ); -// std::string component_dir = std::string( executable_dir ).substr( 0, std::string( executable_dir ).find_last_of("\\/") ); -// component_dir = std::string( component_dir ).substr( 0, std::string( component_dir ).find_last_of("\\/") ); -// component_dir = std::string( component_dir ).substr( 0, std::string( component_dir ).find_last_of("\\/") ); -// component_dir += "\\newview\\app_settings\\mozilla"; - - -#if LL_DARWIN - // For Mac OS, we store both the shared libraries and the runtime files (chrome/, plugins/, etc) in - // Second Life.app/Contents/MacOS/. This matches the way Firefox is distributed on the Mac. - std::string component_dir(gDirUtilp->getExecutableDir()); -#elif LL_WINDOWS - std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) ); - component_dir += gDirUtilp->getDirDelimiter(); - #ifdef LL_DEBUG - component_dir += "mozilla_debug"; - #else // LL_DEBUG - component_dir += "mozilla"; - #endif // LL_DEBUG -#elif LL_LINUX - std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) ); - component_dir += gDirUtilp->getDirDelimiter(); - - #if LINUX64 - component_dir += "mozilla-runtime-linux-x86_64"; - #else - component_dir += "mozilla-runtime-linux-i686"; - #endif - -#elif LL_SOLARIS - std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) ); - component_dir += gDirUtilp->getDirDelimiter(); - #ifdef __sparc - component_dir += "mozilla-solaris-sparc"; - #else - component_dir += "mozilla-solaris-i686"; - #endif -#else - std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) ); - component_dir += gDirUtilp->getDirDelimiter(); - component_dir += "mozilla"; -#endif - - std::string application_dir = gDirUtilp->getExecutableDir(); +void LLViewerMediaImpl::navigateStop() +{ + if(mMediaSource) + { + mMediaSource->browse_stop(); + } - init_data->setBrowserApplicationDir( application_dir ); - std::string profile_dir = gDirUtilp->getExpandedFilename( LL_PATH_MOZILLA_PROFILE, "" ); - init_data->setBrowserProfileDir( profile_dir ); - init_data->setBrowserComponentDir( component_dir ); - std::string profile_name("Second Life"); - init_data->setBrowserProfileName( profile_name ); - init_data->setBrowserParentWindow( gViewerWindow->getMediaWindow() ); +} - // Users can change skins while client is running, so make sure - // we pick up on changes. - gSavedSettings.getControl("SkinCurrent")->getSignal()->connect( - boost::bind( LLViewerMediaImpl::handleSkinCurrentChanged, _1 ) ); +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) +{ + bool result = false; + + if (mMediaSource) + { + // FIXME: THIS IS SO WRONG. + // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... + if( MASK_CONTROL & mask ) + { + if( 'C' == key ) + { + mMediaSource->copy(); + result = true; + } + else + if( 'V' == key ) + { + mMediaSource->paste(); + result = true; + } + else + if( 'X' == key ) + { + mMediaSource->cut(); + result = true; + } + } + + if(!result) + { + + LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); + + result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); + // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here. + (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); + } + } + + return result; +} +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) +{ + bool result = false; + + if (mMediaSource) + { + // only accept 'printable' characters, sigh... + if (uni_char >= 32 // discard 'control' characters + && uni_char != 127) // SDL thinks this is 'delete' - yuck. + { + LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); + + mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); + } + } + + return result; } ////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::cleanupClass() +bool LLViewerMediaImpl::canNavigateForward() { - stop() ; - LLMediaManager::cleanupClass(); + BOOL result = FALSE; + if (mMediaSource) + { + result = mMediaSource->getHistoryForwardAvailable(); + } + return result; } -// static -void LLViewerMedia::play(const std::string& media_url, - const std::string& mime_type, - const LLUUID& placeholder_texture_id, - S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop) +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::canNavigateBack() { - sViewerMediaImpl.play(media_url, mime_type, placeholder_texture_id, - media_width, media_height, media_auto_scale, media_loop); + BOOL result = FALSE; + if (mMediaSource) + { + result = mMediaSource->getHistoryBackAvailable(); + } + return result; } -// static -void LLViewerMedia::stop() + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateMovieImage(const LLUUID& uuid, BOOL active) { - sViewerMediaImpl.stop(); + // IF the media image hasn't changed, do nothing + if (mTextureId == uuid) + { + return; + } + // If we have changed media uuid, restore the old one + if (!mTextureId.isNull()) + { + LLViewerImage* oldImage = LLViewerImage::getImage( mTextureId ); + if (oldImage) + { + oldImage->reinit(mMovieImageHasMips); + oldImage->mIsMediaTexture = FALSE; + } + } + // If the movie is playing, set the new media image + if (active && !uuid.isNull()) + { + LLViewerImage* viewerImage = LLViewerImage::getImage( uuid ); + if( viewerImage ) + { + mTextureId = uuid; + // Can't use mipmaps for movies because they don't update the full image + mMovieImageHasMips = viewerImage->getUseMipMaps(); + viewerImage->reinit(FALSE); + viewerImage->mIsMediaTexture = TRUE; + } + } } -// static -void LLViewerMedia::pause() +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::update() { - sViewerMediaImpl.pause(); + if(mMediaSource == NULL) + { + return; + } + + mMediaSource->idle(); + + if(mMediaSource->isPluginExited()) + { + destroyMediaSource(); + return; + } + + if(!mMediaSource->textureValid()) + { + return; + } + + if(mSuspendUpdates || !mVisible) + { + return; + } + + LLViewerImage* placeholder_image = updatePlaceholderImage(); + + if(placeholder_image) + { + LLRect dirty_rect; + if(mMediaSource->getDirty(&dirty_rect)) + { + // Constrain the dirty rect to be inside the texture + S32 x_pos = llmax(dirty_rect.mLeft, 0); + S32 y_pos = llmax(dirty_rect.mBottom, 0); + S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos; + S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos; + + if(width > 0 && height > 0) + { + + U8* data = mMediaSource->getBitsData(); + + // Offset the pixels pointer to match x_pos and y_pos + data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); + data += ( y_pos * mMediaSource->getTextureDepth() ); + + placeholder_image->setSubImage( + data, + mMediaSource->getBitsWidth(), + mMediaSource->getBitsHeight(), + x_pos, + y_pos, + width, + height, + TRUE); // force a fast update (i.e. don't call analyzeAlpha, etc.) + + } + + mMediaSource->resetDirty(); + } + } } -// static -void LLViewerMedia::start() + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateImagesMediaStreams() { - sViewerMediaImpl.start(); } -// static -void LLViewerMedia::seek(F32 time) + +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerImage* LLViewerMediaImpl::updatePlaceholderImage() { - sViewerMediaImpl.seek(time); + if(mTextureId.isNull()) + { + // The code that created this instance will read from the plugin's bits. + return NULL; + } + + LLViewerImage* placeholder_image = gImageList.getImage( mTextureId ); + + if (mNeedsNewTexture + || placeholder_image->getUseMipMaps() + || ! placeholder_image->mIsMediaTexture + || placeholder_image->getWidth() != mMediaSource->getTextureWidth() + || placeholder_image->getHeight() != mMediaSource->getTextureHeight()) + { + llinfos << "initializing media placeholder" << llendl; + llinfos << "movie image id " << mTextureId << llendl; + + int texture_width = mMediaSource->getTextureWidth(); + int texture_height = mMediaSource->getTextureHeight(); + int texture_depth = mMediaSource->getTextureDepth(); + + // MEDIAOPT: check to see if size actually changed before doing work + placeholder_image->destroyGLTexture(); + // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? + placeholder_image->reinit(FALSE); // probably not needed + + // MEDIAOPT: seems insane that we actually have to make an imageraw then + // immediately discard it + LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth); + raw->clear(0x0f, 0x0f, 0x0f, 0xff); + int discard_level = 0; + + // ask media source for correct GL image format constants + placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), + mMediaSource->getTextureFormatPrimary(), + mMediaSource->getTextureFormatType(), + mMediaSource->getTextureFormatSwapBytes()); + + placeholder_image->createGLTexture(discard_level, raw); + + // placeholder_image->setExplicitFormat() + placeholder_image->setUseMipMaps(FALSE); + + // MEDIAOPT: set this dynamically on play/stop + placeholder_image->mIsMediaTexture = true; + mNeedsNewTexture = false; + } + + return placeholder_image; } -// static -void LLViewerMedia::setVolume(F32 volume) + +////////////////////////////////////////////////////////////////////////////////////////// +LLUUID LLViewerMediaImpl::getMediaTextureID() { - sViewerMediaImpl.setVolume(volume); + return mTextureId; } -// static -LLMediaBase::EStatus LLViewerMedia::getStatus() +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setVisible(bool visible) { - return sViewerMediaImpl.getStatus(); + mVisible = visible; + + if(mVisible) + { + if(mMediaSource && mMediaSource->isPluginExited()) + { + destroyMediaSource(); + } + + if(!mMediaSource) + { + createMediaSource(); + } + } + + if(mMediaSource) + { + mMediaSource->setPriority(mVisible?LLPluginClassMedia::PRIORITY_NORMAL:LLPluginClassMedia::PRIORITY_HIDDEN); + } } ////////////////////////////////////////////////////////////////////////////////////////// -// static -LLUUID LLViewerMedia::getMediaTextureID() +void LLViewerMediaImpl::mouseCapture() { - return sViewerMediaImpl.getMediaTextureID(); + gFocusMgr.setMouseCapture(this); } ////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::getMediaSize(S32 *media_width, S32 *media_height) +void LLViewerMediaImpl::getTextureSize(S32 *texture_width, S32 *texture_height) { - // make sure we're valid + if(mMediaSource && mMediaSource->textureValid()) + { + S32 real_texture_width = mMediaSource->getBitsWidth(); + S32 real_texture_height = mMediaSource->getBitsHeight(); - if ( sViewerMediaImpl.mMediaSource != NULL ) + { + // The "texture width" coming back from the plugin may not be a power of two (thanks to webkit). + // It will be the correct "data width" to pass to setSubImage + int i; + + for(i = 1; i < real_texture_width; i <<= 1) + ; + *texture_width = i; + + for(i = 1; i < real_texture_height; i <<= 1) + ; + *texture_height = i; + } + + } + else { - *media_width = sViewerMediaImpl.mMediaSource->getMediaWidth(); - *media_height = sViewerMediaImpl.mMediaSource->getMediaHeight(); - return true; + *texture_width = 0; + *texture_height = 0; } - return false; +} +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y) +{ +#if 0 + S32 media_width, media_height; + S32 texture_width, texture_height; + getMediaSize( &media_width, &media_height ); + getTextureSize( &texture_width, &texture_height ); + S32 y_delta = texture_height - media_height; + + *mouse_y -= y_delta; +#endif } ////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::getTextureSize(S32 *texture_width, S32 *texture_height) +bool LLViewerMediaImpl::isMediaPlaying() { - if ( sViewerMediaImpl.mMediaSource != NULL ) + bool result = false; + + if(mMediaSource) { - S32 media_width = sViewerMediaImpl.mMediaSource->getMediaWidth(); - S32 media_height = sViewerMediaImpl.mMediaSource->getMediaHeight(); - *texture_width = LLMediaManager::textureWidthFromMediaWidth( media_width ); - *texture_height = LLMediaManager::textureHeightFromMediaHeight( media_height ); - return true; + EMediaStatus status = mMediaSource->getStatus(); + if(status == MEDIA_PLAYING || status == MEDIA_LOADING) + result = true; } - return false; + + return result; } +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::isMediaPaused() +{ + bool result = false; + if(mMediaSource) + { + if(mMediaSource->getStatus() == MEDIA_PAUSED) + result = true; + } + + return result; +} ////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::updateImagesMediaStreams() +// +bool LLViewerMediaImpl::hasMedia() { - sViewerMediaImpl.updateImagesMediaStreams(); + return mMediaSource != NULL; } + ////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isMediaPlaying() +void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event) { - LLMediaBase::EStatus status = sViewerMediaImpl.getStatus(); - return (status == LLMediaBase::STATUS_STARTED ); + switch(event) + { + case MEDIA_EVENT_PLUGIN_FAILED: + { + LLSD args; + args["PLUGIN"] = LLMIMETypes::implType(mMimeType); + LLNotifications::instance().add("MediaPluginFailed", args); + } + break; + default: + break; + } + // Just chain the event to observers. + emitEvent(self, event); } -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isMediaPaused() + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::cut() { - LLMediaBase::EStatus status = sViewerMediaImpl.getStatus(); - return (status == LLMediaBase::STATUS_PAUSED); + if (mMediaSource) + mMediaSource->cut(); } -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::hasMedia() + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canCut() const { - return sViewerMediaImpl.mMediaSource != NULL; + if (mMediaSource) + return mMediaSource->canCut(); + else + return FALSE; } -////////////////////////////////////////////////////////////////////////////////////////// -//static -bool LLViewerMedia::isActiveMediaTexture(const LLUUID& id) +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::copy() { - return (id.notNull() - && id == getMediaTextureID() - && isMediaPlaying()); + if (mMediaSource) + mMediaSource->copy(); } -////////////////////////////////////////////////////////////////////////////////////////// -// static -std::string LLViewerMedia::getMediaURL() +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canCopy() const { - return sViewerMediaImpl.mMediaURL; + if (mMediaSource) + return mMediaSource->canCopy(); + else + return FALSE; } -////////////////////////////////////////////////////////////////////////////////////////// -// static -std::string LLViewerMedia::getMimeType() + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::paste() { - return sViewerMediaImpl.mMimeType; + if (mMediaSource) + mMediaSource->paste(); } -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setMimeType(std::string mime_type) + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canPaste() const { - sViewerMediaImpl.mMimeType = mime_type; + if (mMediaSource) + return mMediaSource->canPaste(); + else + return FALSE; } + diff --git a/linden/indra/newview/llviewermedia.h b/linden/indra/newview/llviewermedia.h index 600d7409e..afda426af 100644 --- a/linden/indra/newview/llviewermedia.h +++ b/linden/indra/newview/llviewermedia.h @@ -33,50 +33,192 @@ #ifndef LLVIEWERMEDIA_H #define LLVIEWERMEDIA_H -#include "llmediabase.h" // for status codes +#include "llfocusmgr.h" -class LLMediaManagerData; +#include "llpanel.h" +#include "llpluginclassmediaowner.h" + +#include "llviewermediaobserver.h" + +class LLViewerMediaImpl; class LLUUID; +class LLViewerImage; + +typedef LLPointer<LLViewerMediaImpl> viewer_media_t; +/////////////////////////////////////////////////////////////////////////////// +// +class LLViewerMediaEventEmitter +{ +public: + virtual ~LLViewerMediaEventEmitter(); + + bool addObserver( LLViewerMediaObserver* subject ); + bool remObserver( LLViewerMediaObserver* subject ); + void emitEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event); + +private: + typedef std::list< LLViewerMediaObserver* > observerListType; + observerListType mObservers; +}; class LLViewerMedia { + LOG_CLASS(LLViewerMedia); public: // Special case early init for just web browser component // so we can show login screen. See .cpp file for details. JC - static void initBrowser(); - static void initClass(); - static void cleanupClass(); + static viewer_media_t newMediaImpl(const std::string& media_url, + const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop, + std::string mime_type = "none/none"); - static void play(const std::string& media_url, - const std::string& mime_type, - const LLUUID& placeholder_texture_id, - S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop); - static void stop(); - static void pause(); - static void start(); - static void seek(F32 time); + static void removeMedia(LLViewerMediaImpl* media); + static LLViewerMediaImpl* getMediaImplFromTextureID(const LLUUID& texture_id); + static std::string getCurrentUserAgent(); + static void updateBrowserUserAgent(); + static bool handleSkinCurrentChanged(const LLSD& /*newvalue*/); + static bool textureHasMedia(const LLUUID& texture_id); static void setVolume(F32 volume); - static LLMediaBase::EStatus getStatus(); - static LLUUID getMediaTextureID(); - static bool getMediaSize(S32 *media_width, S32 *media_height); - static bool getTextureSize(S32 *texture_width, S32 *texture_height); - static bool isMediaPlaying(); - static bool isMediaPaused(); - static bool hasMedia(); - static bool isActiveMediaTexture(const LLUUID& id); + static void updateMedia(); + + static void cleanupClass(); + +}; + +// Implementation functions not exported into header file +class LLViewerMediaImpl + : public LLMouseHandler, public LLRefCount, public LLPluginClassMediaOwner, public LLViewerMediaEventEmitter, public LLEditMenuHandler +{ + LOG_CLASS(LLViewerMediaImpl); +public: + + LLViewerMediaImpl(const std::string& media_url, + const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop, + const std::string& mime_type); + + ~LLViewerMediaImpl(); + void createMediaSource(); + void destroyMediaSource(); + void setMediaType(const std::string& media_type); + bool initializeMedia(const std::string& mime_type); + bool initializePlugin(const std::string& media_type); + LLPluginClassMedia* getMediaPlugin() { return mMediaSource; } + void setSize(int width, int height); + + void play(); + void stop(); + void pause(); + void start(); + void seek(F32 time); + void setVolume(F32 volume); + void focus(bool focus); + void mouseDown(S32 x, S32 y); + void mouseUp(S32 x, S32 y); + void mouseMove(S32 x, S32 y); + void mouseLeftDoubleClick(S32 x,S32 y ); + void mouseCapture(); + + void navigateHome(); + void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false); + void navigateStop(); + bool handleKeyHere(KEY key, MASK mask); + bool handleUnicodeCharHere(llwchar uni_char); + bool canNavigateForward(); + bool canNavigateBack(); + std::string getMediaURL() { return mMediaURL; } + std::string getMediaHomeURL() { return mHomeURL; } + std::string getMimeType() { return mMimeType; } + void getTextureSize(S32 *texture_width, S32 *texture_height); + void scaleMouse(S32 *mouse_x, S32 *mouse_y); + + void update(); + void updateMovieImage(const LLUUID& image_id, BOOL active); + void updateImagesMediaStreams(); + LLUUID getMediaTextureID(); + + void suspendUpdates(bool suspend) { mSuspendUpdates = suspend; }; + void setVisible(bool visible); + + bool isMediaPlaying(); + bool isMediaPaused(); + bool hasMedia(); + + // utility function to create a ready-to-use media instance from a desired media type. + static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height); + + // Internally set our desired browser user agent string, including + // the Second Life version and skin name. Used because we can + // switch skins without restarting the app. + static void updateBrowserUserAgent(); + + // Callback for when the SkinCurrent control is changed to + // switch the user agent string to indicate the new skin. + static bool handleSkinCurrentChanged(const LLSD& newvalue); + + // need these to handle mouseup... + /*virtual*/ void onMouseCaptureLost(); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + + // Grr... the only thing I want as an LLMouseHandler are the onMouseCaptureLost and handleMouseUp calls. + // Sadly, these are all pure virtual, so I have to supply implementations here: + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; }; + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) { return FALSE; }; + /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask) {return FALSE; }; + /*virtual*/ const std::string& getName() const { return LLStringUtil::null; }; + /*virtual*/ BOOL isView() const { return FALSE; }; + /*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const {}; + /*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const {}; + /*virtual*/ BOOL hasMouseCapture() { return gFocusMgr.getMouseCapture() == this; }; + + // Inherited from LLPluginClassMediaOwner + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent); + + // LLEditMenuHandler overrides + /*virtual*/ void cut(); + /*virtual*/ BOOL canCut() const; + + /*virtual*/ void copy(); + /*virtual*/ BOOL canCopy() const; - static std::string getMediaURL(); - static std::string getMimeType(); - static void setMimeType(std::string mime_type); + /*virtual*/ void paste(); + /*virtual*/ BOOL canPaste() const; + +public: + // a single media url with some data and an impl. + LLPluginClassMedia* mMediaSource; + LLUUID mTextureId; + bool mMovieImageHasMips; + std::string mMediaURL; + std::string mHomeURL; + std::string mMimeType; + S32 mLastMouseX; // save the last mouse coord we get, so when we lose capture we can simulate a mouseup at that point. + S32 mLastMouseY; + S32 mMediaWidth; + S32 mMediaHeight; + bool mMediaAutoScale; + bool mMediaLoop; + bool mNeedsNewTexture; + bool mSuspendUpdates; + bool mVisible; - static void updateImagesMediaStreams(); - private: - // Fill in initialization data for LLMediaManager::initClass() - static void buildMediaManagerData( LLMediaManagerData* init_data ); +private: + LLViewerImage *updatePlaceholderImage(); }; #endif // LLVIEWERMEDIA_H diff --git a/linden/indra/newview/llviewermedia_streamingaudio.cpp b/linden/indra/newview/llviewermedia_streamingaudio.cpp new file mode 100644 index 000000000..575dbc8d8 --- /dev/null +++ b/linden/indra/newview/llviewermedia_streamingaudio.cpp @@ -0,0 +1,189 @@ +/** + * @file llviewermedia_streamingaudio.h + * @author Tofu Linden, Sam Kolb + * @brief LLStreamingAudio_MediaPlugins implementation - an implementation of the streaming audio interface which is implemented as a client of the media plugins API. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "linden_common.h" +#include "llpluginclassmedia.h" +#include "llviewermedia.h" +#include "llviewercontrol.h" + +#include "llviewermedia_streamingaudio.h" + +#include "llmimetypes.h" +#include "llvfs.h" +#include "lldir.h" + +#include "llchat.h" +#include "llfloaterchat.h" + +LLStreamingAudio_MediaPlugins::LLStreamingAudio_MediaPlugins() : + mMediaPlugin(NULL), + mGain(1.0) +{ + // nothing interesting to do? + // we will lazily create a media plugin at play-time, if none exists. +} + +LLStreamingAudio_MediaPlugins::~LLStreamingAudio_MediaPlugins() +{ + delete mMediaPlugin; + mMediaPlugin = NULL; +} + +void LLStreamingAudio_MediaPlugins::start(const std::string& url) +{ + if (!mMediaPlugin) // lazy-init the underlying media plugin + { + mMediaPlugin = initializeMedia("audio/mpeg"); // assumes that whatever media implementation supports mp3 also supports vorbis. + llinfos << "mMediaPlugin is now " << mMediaPlugin << llendl; + } + + if(!mMediaPlugin) + return; + + if (!url.empty()) { + llinfos << "Starting internet stream: " << url << llendl; + mURL = url; + mMediaPlugin->loadURI ( url ); + mMediaPlugin->start(); + llinfos << "Playing....." << llendl; + } else { + llinfos << "setting stream to NULL"<< llendl; + mURL.clear(); + mMediaPlugin->stop(); + } +} + +void LLStreamingAudio_MediaPlugins::stop() +{ + if(mMediaPlugin) + { + mMediaPlugin->stop(); + } + + mURL.clear(); +} + +void LLStreamingAudio_MediaPlugins::pause(int pause) +{ + if(!mMediaPlugin) + return; + + if(pause) + { + mMediaPlugin->pause(); + } + else + { + mMediaPlugin->start(); + } +} + +void LLStreamingAudio_MediaPlugins::update() +{ + if (mMediaPlugin) + mMediaPlugin->idle(); +} + +int LLStreamingAudio_MediaPlugins::isPlaying() +{ + if (!mMediaPlugin) + return 0; + + // *TODO: can probably do better than this + if (mMediaPlugin->isPluginRunning()) + { + return 1; // Active and playing + } + + if (mMediaPlugin->isPluginExited()) + { + return 0; // stopped + } + + return 2; // paused +} + +void LLStreamingAudio_MediaPlugins::setGain(F32 vol) +{ + mGain = vol; + + if(!mMediaPlugin) + return; + + vol = llclamp(vol, 0.f, 1.f); + mMediaPlugin->setVolume(vol); +} + +F32 LLStreamingAudio_MediaPlugins::getGain() +{ + return mGain; +} + +std::string LLStreamingAudio_MediaPlugins::getURL() +{ + return mURL; +} + +void LLStreamingAudio_MediaPlugins::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + if (event == MEDIA_EVENT_NAME_CHANGED) + { + std::string title = self->getMediaName(); + if (!title.empty() && gSavedSettings.getBOOL("ShowStreamTitle")) + { + //llinfos << "Playing: " << title << llendl; + LLChat chat; + //TODO: set this in XUI + std::string playing_msg = "Playing: " + title; + chat.mText = playing_msg; + LLFloaterChat::addChat(chat, FALSE, FALSE); + } + } +} + +LLPluginClassMedia* LLStreamingAudio_MediaPlugins::initializeMedia(const std::string& media_type) +{ + LLPluginClassMediaOwner* owner = this; + S32 default_size = 1; // audio-only - be minimal, doesn't matter + LLPluginClassMedia* media_source = LLViewerMediaImpl::newSourceFromMediaType(media_type, owner, default_size, default_size); + + if (media_source) + { + media_source->setLoop(false); // audio streams are not expected to loop + } + + return media_source; +} + diff --git a/linden/indra/newview/llviewermedia_streamingaudio.h b/linden/indra/newview/llviewermedia_streamingaudio.h new file mode 100644 index 000000000..816e21361 --- /dev/null +++ b/linden/indra/newview/llviewermedia_streamingaudio.h @@ -0,0 +1,73 @@ +/** + * @file llviewermedia_streamingaudio.h + * @author Tofu Linden + * @brief Definition of LLStreamingAudio_MediaPlugins implementation - an implementation of the streaming audio interface which is implemented as a client of the media plugins API. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_VIEWERMEDIA_STREAMINGAUDIO_H +#define LL_VIEWERMEDIA_STREAMINGAUDIO_H + + +#include "stdtypes.h" // from llcommon +#include "llstreamingaudio.h" + +class LLPluginClassMedia; + +class LLStreamingAudio_MediaPlugins : + public LLStreamingAudioInterface, + public LLPluginClassMediaOwner +{ + public: + LLStreamingAudio_MediaPlugins(); + /*virtual*/ ~LLStreamingAudio_MediaPlugins(); + + /*virtual*/ void start(const std::string& url); + /*virtual*/ void stop(); + /*virtual*/ void pause(int pause); + /*virtual*/ void update(); + /*virtual*/ int isPlaying(); + /*virtual*/ void setGain(F32 vol); + /*virtual*/ F32 getGain(); + /*virtual*/ std::string getURL(); + + // inherited from LLPluginClassMediaOwner + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + +private: + LLPluginClassMedia* initializeMedia(const std::string& media_type); + + LLPluginClassMedia *mMediaPlugin; + std::string mURL; + F32 mGain; +}; + + + +#endif //LL_VIEWERMEDIA_STREAMINGAUDIO_H diff --git a/linden/indra/newview/llviewermediafocus.cpp b/linden/indra/newview/llviewermediafocus.cpp new file mode 100644 index 000000000..2e372a1ca --- /dev/null +++ b/linden/indra/newview/llviewermediafocus.cpp @@ -0,0 +1,359 @@ +/** + * @file llviewermediafocus.cpp + * @brief Governs focus on Media prims + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewermediafocus.h" + +//LLViewerMediaFocus +#include "llviewerobjectlist.h" +#include "llpanelmediahud.h" +#include "llpluginclassmedia.h" +#include "llagent.h" +#include "lltoolpie.h" +#include "llviewercamera.h" +#include "llviewermedia.h" +#include "llhudview.h" +#include "lluictrlfactory.h" +#include "lldrawable.h" +#include "llparcel.h" +#include "llviewerparcelmgr.h" +#include "llweb.h" +// +// LLViewerMediaFocus +// + +LLViewerMediaFocus::LLViewerMediaFocus() +: mMouseOverFlag(false) +{ +} + +LLViewerMediaFocus::~LLViewerMediaFocus() +{ + // The destructor for LLSingletons happens at atexit() time, which is too late to do much. + // Clean up in cleanupClass() instead. +} + +void LLViewerMediaFocus::cleanupClass() +{ + LLViewerMediaFocus *self = LLViewerMediaFocus::getInstance(); + + if(self) + { + // mMediaHUD will have been deleted by this point -- don't try to delete it. + + /* Richard says: + all widgets are supposed to be destroyed at the same time + you shouldn't hold on to pointer to them outside of ui code + you can use the LLHandle approach + if you want to be type safe, you'll need to add a LLRootHandle to whatever derived class you are pointing to + look at llview::gethandle + its our version of a weak pointer + */ + if(self->mMediaHUD.get()) + { + self->mMediaHUD.get()->setMediaImpl(NULL); + } + self->mMediaImpl = NULL; + } + +} + + +void LLViewerMediaFocus::setFocusFace( BOOL b, LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl ) +{ + LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (b && media_impl.notNull()) + { + mMediaImpl = media_impl; + LLSelectMgr::getInstance()->deselectAll(); + LLSelectMgr::getInstance()->selectObjectOnly(objectp, face); + + mFocus = LLSelectMgr::getInstance()->getSelection(); + if(mMediaHUD.get() && ! parcel->getMediaPreventCameraZoom()) + { + mMediaHUD.get()->resetZoomLevel(); + mMediaHUD.get()->nextZoomLevel(); + } + if (!mFocus->isEmpty()) + { + gFocusMgr.setKeyboardFocus(this); + } + mObjectID = objectp->getID(); + // LLViewerMedia::addObserver(this, mObjectID); + + + } + else + { + gFocusMgr.setKeyboardFocus(NULL); + if(! parcel->getMediaPreventCameraZoom()) + { + if (!mFocus->isEmpty()) + { + gAgent.setFocusOnAvatar(TRUE, ANIMATE); + } + } + mFocus = NULL; + // LLViewerMedia::remObserver(this, mObjectID); + + // Null out the media hud media pointer + if(mMediaHUD.get()) + { + mMediaHUD.get()->setMediaImpl(NULL); + } + + // and null out the media impl + mMediaImpl = NULL; + } + if(mMediaHUD.get()) + { + mMediaHUD.get()->setMediaFocus(b); + } +} +bool LLViewerMediaFocus::getFocus() +{ + if (gFocusMgr.getKeyboardFocus() == this) + { + return true; + } + return false; +} + +// This function selects an ideal viewing distance given a selection bounding box, normal, and padding value +void LLViewerMediaFocus::setCameraZoom(F32 padding_factor) +{ + LLPickInfo& pick = LLToolPie::getInstance()->getPick(); + + if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + pick = mPickInfo; + setFocusFace(true, pick.getObject(), pick.mObjectFace, mMediaImpl); + } + + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + gAgent.setFocusOnAvatar(FALSE, ANIMATE); + + LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); + F32 height; + F32 width; + F32 depth; + F32 angle_of_view; + F32 distance; + + // We need the aspect ratio, and the 3 components of the bbox as height, width, and depth. + F32 aspect_ratio = getBBoxAspectRatio(selection_bbox, pick.mNormal, &height, &width, &depth); + F32 camera_aspect = LLViewerCamera::getInstance()->getAspect(); + + // We will normally use the side of the volume aligned with the short side of the screen (i.e. the height for + // a screen in a landscape aspect ratio), however there is an edge case where the aspect ratio of the object is + // more extreme than the screen. In this case we invert the logic, using the longer component of both the object + // and the screen. + bool invert = (camera_aspect > 1.0f && aspect_ratio > camera_aspect) || + (camera_aspect < 1.0f && aspect_ratio < camera_aspect); + + // To calculate the optimum viewing distance we will need the angle of the shorter side of the view rectangle. + // In portrait mode this is the width, and in landscape it is the height. + // We then calculate the distance based on the corresponding side of the object bbox (width for portrait, height for landscape) + // We will add half the depth of the bounding box, as the distance projection uses the center point of the bbox. + if(camera_aspect < 1.0f || invert) + { + angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect()); + distance = width * 0.5 * padding_factor / tan(angle_of_view * 0.5f ); + } + else + { + angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView()); + distance = height * 0.5 * padding_factor / tan(angle_of_view * 0.5f ); + } + + distance += depth * 0.5; + + // Finally animate the camera to this new position and focal point + gAgent.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(pick.mNormal * distance), + LLSelectMgr::getInstance()->getSelectionCenterGlobal(), LLSelectMgr::getInstance()->getSelection()->getFirstObject()->mID ); + } +} +void LLViewerMediaFocus::onFocusReceived() +{ + if(mMediaImpl.notNull()) + mMediaImpl->focus(true); + + LLFocusableElement::onFocusReceived(); +} + +void LLViewerMediaFocus::onFocusLost() +{ + if(mMediaImpl.notNull()) + mMediaImpl->focus(false); + gViewerWindow->focusClient(); + mFocus = NULL; + LLFocusableElement::onFocusLost(); +} +void LLViewerMediaFocus::setMouseOverFlag(bool b, viewer_media_t media_impl) +{ + if (b && media_impl.notNull()) + { + if(! mMediaHUD.get()) + { + LLPanelMediaHUD* media_hud = new LLPanelMediaHUD(mMediaImpl); + mMediaHUD = media_hud->getHandle(); + gHUDView->addChild(media_hud); + } + mMediaHUD.get()->setMediaImpl(media_impl); + mMediaImpl = media_impl; + } + mMouseOverFlag = b; +} +LLUUID LLViewerMediaFocus::getSelectedUUID() +{ + LLViewerObject* object = mFocus->getFirstObject(); + return object ? object->getID() : LLUUID::null; +} +#if 0 // Must re-implement when the new media api event system is ready +void LLViewerMediaFocus::onNavigateComplete( const EventType& event_in ) +{ + if (hasFocus() && mLastURL != event_in.getStringValue()) + { + LLViewerMedia::focus(true, mObjectID); + // spoof mouse event to reassert focus + LLViewerMedia::mouseDown(1,1, mObjectID); + LLViewerMedia::mouseUp(1,1, mObjectID); + } + mLastURL = event_in.getStringValue(); +} +#endif +BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ + if(mMediaImpl.notNull()) + mMediaImpl->handleKeyHere(key, mask); + return true; +} + +BOOL LLViewerMediaFocus::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) +{ + if(mMediaImpl.notNull()) + mMediaImpl->handleUnicodeCharHere(uni_char); + return true; +} +BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + BOOL retval = FALSE; + if(mFocus.notNull() && mMediaImpl.notNull() && mMediaImpl->hasMedia()) + { + mMediaImpl->getMediaPlugin()->scrollEvent(x, y, clicks); + retval = TRUE; + } + return retval; +} + +void LLViewerMediaFocus::update() +{ + if (mMediaHUD.get()) + { + if(mFocus.notNull() || mMouseOverFlag || mMediaHUD.get()->isMouseOver()) + { + // mMediaHUD.get()->setVisible(true); + mMediaHUD.get()->updateShape(); + } + else + { + mMediaHUD.get()->setVisible(false); + } + } +} +// This function calculates the aspect ratio and the world aligned components of a selection bounding box. +F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth) +{ + // Convert the selection normal and an up vector to local coordinate space of the bbox + LLVector3 local_normal = bbox.agentToLocalBasis(normal); + LLVector3 z_vec = bbox.agentToLocalBasis(LLVector3(0.0f, 0.0f, 1.0f)); + + LLVector3 comp1(0.f,0.f,0.f); + LLVector3 comp2(0.f,0.f,0.f); + LLVector3 bbox_max = bbox.getExtentLocal(); + F32 dot1 = 0.f; + F32 dot2 = 0.f; + + // The largest component of the localized normal vector is the depth component + // meaning that the other two are the legs of the rectangle. + local_normal.abs(); + if(local_normal.mV[VX] > local_normal.mV[VY]) + { + if(local_normal.mV[VX] > local_normal.mV[VZ]) + { + // Use the y and z comps + comp1.mV[VY] = bbox_max.mV[VY]; + comp2.mV[VZ] = bbox_max.mV[VZ]; + *depth = bbox_max.mV[VX]; + } + else + { + // Use the x and y comps + comp1.mV[VY] = bbox_max.mV[VY]; + comp2.mV[VZ] = bbox_max.mV[VZ]; + *depth = bbox_max.mV[VZ]; + } + } + else if(local_normal.mV[VY] > local_normal.mV[VZ]) + { + // Use the x and z comps + comp1.mV[VX] = bbox_max.mV[VX]; + comp2.mV[VZ] = bbox_max.mV[VZ]; + *depth = bbox_max.mV[VY]; + } + else + { + // Use the x and y comps + comp1.mV[VY] = bbox_max.mV[VY]; + comp2.mV[VZ] = bbox_max.mV[VZ]; + *depth = bbox_max.mV[VX]; + } + + // The height is the vector closest to vertical in the bbox coordinate space (highest dot product value) + dot1 = comp1 * z_vec; + dot2 = comp2 * z_vec; + if(fabs(dot1) > fabs(dot2)) + { + *height = comp1.length(); + *width = comp2.length(); + } + else + { + *height = comp2.length(); + *width = comp1.length(); + } + + // Return the aspect ratio. + return *width / *height; +} diff --git a/linden/indra/newview/llviewermediafocus.h b/linden/indra/newview/llviewermediafocus.h new file mode 100644 index 000000000..ed9597e61 --- /dev/null +++ b/linden/indra/newview/llviewermediafocus.h @@ -0,0 +1,91 @@ +/** + * @file llpanelmsgs.h + * @brief Message popup preferences panel + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_VIEWERMEDIAFOCUS_H +#define LL_VIEWERMEDIAFOCUS_H + +// includes for LLViewerMediaFocus +#include "llfocusmgr.h" +#include "llviewermedia.h" +#include "llviewerobject.h" +#include "llviewerwindow.h" +#include "llselectmgr.h" + +class LLViewerMediaImpl; +class LLPanelMediaHUD; + +class LLViewerMediaFocus : + public LLFocusableElement, + public LLSingleton<LLViewerMediaFocus> +{ +public: + LLViewerMediaFocus(); + ~LLViewerMediaFocus(); + + static void cleanupClass(); + + void setFocusFace(BOOL b, LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl); + void clearFocus() { setFocusFace(false, NULL, 0, NULL); } + /*virtual*/ bool getFocus(); + /*virtual*/ // void onNavigateComplete( const EventType& event_in ); + + /*virtual*/ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + /*virtual*/ BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + + LLUUID getSelectedUUID(); + LLObjectSelectionHandle getSelection() { return mFocus; } + + void update(); + + void setCameraZoom(F32 padding_factor); + void setMouseOverFlag(bool b, viewer_media_t media_impl = NULL); + bool getMouseOverFlag() { return mMouseOverFlag; } + void setPickInfo(LLPickInfo pick_info) { mPickInfo = pick_info; } + F32 getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth); + +protected: + /*virtual*/ void onFocusReceived(); + /*virtual*/ void onFocusLost(); + +private: + LLObjectSelectionHandle mFocus; + std::string mLastURL; + bool mMouseOverFlag; + LLPickInfo mPickInfo; + LLHandle<LLPanelMediaHUD> mMediaHUD; + LLUUID mObjectID; + viewer_media_t mMediaImpl; +}; + + +#endif // LL_VIEWERMEDIAFOCUS_H diff --git a/linden/indra/llmedia/llmediaimplexample1.h b/linden/indra/newview/llviewermediaobserver.h similarity index 56% rename from linden/indra/llmedia/llmediaimplexample1.h rename to linden/indra/newview/llviewermediaobserver.h index 1b90e9378..6667f982b 100644 --- a/linden/indra/llmedia/llmediaimplexample1.h +++ b/linden/indra/newview/llviewermediaobserver.h @@ -1,6 +1,6 @@ /** - * @file llmediaimplexample1.h - * @brief Example 1 of a media impl concrete class + * @file llviewermediaobserver.h + * @brief Methods to override to catch events from LLViewerMedia class * * $LicenseInfo:firstyear=2007&license=viewergpl$ * @@ -30,44 +30,42 @@ * $/LicenseInfo$ */ -#ifndef LLMEDIAIMPLEXAMPLE1_H -#define LLMEDIAIMPLEXAMPLE1_H +#ifndef LLVIEWERMEDIAOBSERVER_H +#define LLVIEWERMEDIAOBSERVER_H -#include "llmediaimplcommon.h" -#include "llmediaimplfactory.h" +#include "llpluginclassmediaowner.h" -class LLMediaManagerData; +class LLViewerMediaEventEmitter; -class LLMediaImplExample1 : - public LLMediaImplCommon +class LLViewerMediaObserver : public LLPluginClassMediaOwner { - public: - LLMediaImplExample1(); +public: + virtual ~LLViewerMediaObserver(); + +private: + // Emitters will manage this list in addObserver/remObserver. + friend class LLViewerMediaEventEmitter; + std::list<LLViewerMediaEventEmitter *> mEmitters; +}; - static bool startup( LLMediaManagerData* init_data ); - static bool closedown(); - /* virtual */ bool init(); - /* virtual */ bool navigateTo( const std::string url ); - /* virtual */ bool updateMedia(); - /* virtual */ std::string getVersion(); - /* virtual */ unsigned char* getMediaData(); - /* virtual */ bool reset(); - /* virtual */ bool mouseMove( int x_pos, int y_pos ); - /* virtual */ bool setRequestedMediaSize( int width, int height ); +#if 0 + // Classes that inherit from LLViewerMediaObserver should add this to their class declaration: + + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + + /* and will probably need to add this to their cpp file: - private: - unsigned char* mMediaPixels; -}; + #include "llpluginclassmedia.h" -class LLMediaImplExample1Maker : public LLMediaImplMaker -{ - public: - LLMediaImplExample1Maker(); - LLMediaImplExample1* create() - { - return new LLMediaImplExample1(); - } -}; + */ + + // The list of events is in llpluginclassmediaowner.h + + +#endif + + +#endif // LLVIEWERMEDIAOBSERVER_H -#endif // LLMEDIAIMPLEXAMPLE1_H diff --git a/linden/indra/newview/llviewermenu.cpp b/linden/indra/newview/llviewermenu.cpp index 524654a28..503613ecd 100644 --- a/linden/indra/newview/llviewermenu.cpp +++ b/linden/indra/newview/llviewermenu.cpp @@ -40,7 +40,7 @@ #include <sstream> // linden library includes -#include "audioengine.h" +#include "llaudioengine.h" #include "indra_constants.h" #include "llassetstorage.h" #include "llchat.h" @@ -111,9 +111,8 @@ #include "llfloatergroupinfo.h" #include "llfloatergroupinvite.h" #include "llfloatergroups.h" -#include "llfloaterhtml.h" #include "llfloaterhtmlcurrency.h" -#include "llfloaterhtmlhelp.h" // gViewerHtmlHelp +#include "llfloatermediabrowser.h" // gViewerHtmlHelp #include "llfloaterhtmlsimple.h" #include "llfloaterhud.h" #include "llfloaterinspect.h" @@ -121,6 +120,8 @@ #include "llfloaterland.h" #include "llfloaterlandholdings.h" #include "llfloatermap.h" +#include "llfloatermessagebuilder.h" +#include "llfloatermessagelog.h" #include "llfloatermute.h" #include "llfloateropenobject.h" #include "llfloaterpermissionsmgr.h" @@ -158,6 +159,7 @@ #include "lllineeditor.h" #include "llmenucommands.h" #include "llmenugl.h" +#include "llmimetypes.h" #include "llmorphview.h" #include "llmoveview.h" #include "llmutelist.h" @@ -226,8 +228,8 @@ #include "jcfloater_animation_list.h" #include "llfloaterassetbrowser.h" -#include "hippoGridManager.h" -#include "hippoLimits.h" +#include "hippogridmanager.h" +#include "hippolimits.h" #include "llfloaterteleporthistory.h" @@ -394,6 +396,8 @@ void handle_god_mode(void*); // God menu void handle_leave_god_mode(void*); +void handle_open_message_log(void*); +void handle_open_message_builder(void*); BOOL is_inventory_visible( void* user_data ); void handle_reset_view(); @@ -776,6 +780,11 @@ void init_client_menu(LLMenuGL* menu) &handle_show_notifications_console, NULL, NULL, '5', MASK_CONTROL|MASK_SHIFT )); + sub->appendSeparator(); + + sub->append(new LLMenuItemCallGL( "Message Log", &handle_open_message_log, NULL)); + sub->append(new LLMenuItemCallGL( "Message Builder", &handle_open_message_builder, NULL)); + sub->appendSeparator(); sub->append(new LLMenuItemCallGL("Region Info to Debug Console", @@ -935,6 +944,14 @@ void init_client_menu(LLMenuGL* menu) menu->appendMenu( sub ); sub->createJumpKeys(); } + { + LLMenuGL* sub = NULL; + sub = new LLMenuGL("Media"); + sub->append(new LLMenuItemCallGL("Reload MIME types", &LLMIMETypes::reload)); + sub->append(new LLMenuItemCallGL("Web Browser Test", &handle_web_browser_test)); + menu->appendMenu( sub ); + sub->createJumpKeys(); + } menu->appendSeparator(); @@ -1065,6 +1082,7 @@ void init_debug_ui_menu(LLMenuGL* menu) menu->appendSeparator(); menu->append(new LLMenuItemCallGL("Web Browser Test", &handle_web_browser_test)); + // commented out until work is complete: DEV-32268 // menu->append(new LLMenuItemCallGL("Buy Currency Test", &handle_buy_currency_test)); menu->append(new LLMenuItemCallGL("Editable UI", &edit_ui)); @@ -3280,6 +3298,16 @@ void process_grant_godlike_powers(LLMessageSystem* msg, void**) } } + +void handle_open_message_log(void*) +{ + LLFloaterMessageLog::show(); +} + +void handle_open_message_builder(void*) +{ + LLFloaterMessageBuilder::show(""); +} /* class LLHaveCallingcard : public LLInventoryCollectFunctor { @@ -5486,6 +5514,7 @@ class LLWorldSetAway : public view_listener_t if (gAgent.getAFK()) { gAgent.clearAFK(); + llinfos << "Spawning HTML help window" << llendl; } else { @@ -6064,7 +6093,15 @@ class LLShowFloater : public view_listener_t } else if (floater_name == "inworld browser") { - LLFloaterMediaBrowser::toggleInstance(LLSD()); + if (LLFloaterMediaBrowser::instanceVisible()) + { + LLFloaterMediaBrowser::getInstance()->close(); + } + else + { + // MoonWorld: Even in this case, open BrowserHome in the external browser instead of the internal browser. + LLWeb::loadURL(gSavedSettings.getString("BrowserHome")); + } } else if (floater_name == "beacons") { @@ -6134,6 +6171,10 @@ class LLFloaterVisible : public view_listener_t LLInventoryView* iv = LLInventoryView::getActiveInventory(); new_value = (NULL != iv && TRUE == iv->getVisible()); } + else if (floater_name == "inworld browser") + { + new_value = LLFloaterMediaBrowser::instanceVisible(); + } else if (floater_name == "areasearch") { JCFloaterAreaSearch* instn = JCFloaterAreaSearch::getInstance(); @@ -6669,7 +6710,7 @@ class LLWornItemFetchedObserver : public LLInventoryFetchObserver protected: virtual void done() { - gPieAttachment->buildDrawLabels(); + if (gPieAttachment) gPieAttachment->buildDrawLabels(); gInventory.removeObserver(this); delete this; } @@ -7871,7 +7912,7 @@ void handle_grab_texture(void* data) // user know that the image is now in inventory. if(view) { - LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); view->getPanel()->setSelection(item_id, TAKE_FOCUS_NO); view->getPanel()->openSelected(); @@ -8075,13 +8116,7 @@ void handle_load_from_xml(void*) void handle_web_browser_test(void*) { - const bool open_links_externally = false; - const bool open_app_slurls = true; - LLFloaterHtml::getInstance()->show( - "http://secondlife.com/app/search/slurls.html", - "Web Browser Test", - open_links_externally, - open_app_slurls); + LLWeb::loadURL("http://secondlife.com/app/search/slurls.html"); } void handle_buy_currency_test(void*) @@ -8672,6 +8707,30 @@ class LLAdvancedDumpInfoToConsole : public view_listener_t +///////////////////////// +// MESSAGE LOG/BUILDER // +///////////////////////// + + +class LLMessageLogBuilder : public view_listener_t +{ + bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) + { + std::string info_type = userdata.asString(); + if ("MessageLog" == info_type) + { + handle_open_message_log(NULL); + } + else if ("MessageBuilder" == info_type) + { + handle_open_message_builder(NULL); + } + return true; + } +}; + + + /////////////////////////////// // RELOAD SETTINGS OVERRIDES // /////////////////////////////// @@ -11260,6 +11319,8 @@ void initialize_menus() addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole"); addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole"); addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole"); + addMenu(new LLMessageLogBuilder(), "Advanced.MessageLog"); + addMenu(new LLMessageLogBuilder(), "Advanced.MessageBuilder"); addMenu(new LLAdvancedReloadSettingsOverrides(), "Advanced.ReloadSettingsOverrides"); addMenu(new LLAdvancedToggleSit(), "Advanced.ToggleSit"); addMenu(new LLAdvancedCheckSit(), "Advanced.CheckSit"); diff --git a/linden/indra/newview/llviewermenu.h b/linden/indra/newview/llviewermenu.h index 632f783d5..f33c20172 100644 --- a/linden/indra/newview/llviewermenu.h +++ b/linden/indra/newview/llviewermenu.h @@ -110,6 +110,8 @@ bool handle_give_money_dialog(); bool handle_object_open(); bool handle_go_to_confirm(); bool handle_go_to(); +void handle_open_message_log(void*); +void handle_open_message_builder(void*); // Export to XML or Collada void handle_export_selected( void * ); diff --git a/linden/indra/newview/llviewermenufile.cpp b/linden/indra/newview/llviewermenufile.cpp index 1981bb990..b88b5ca53 100644 --- a/linden/indra/newview/llviewermenufile.cpp +++ b/linden/indra/newview/llviewermenufile.cpp @@ -67,7 +67,7 @@ #include "llstring.h" #include "lltransactiontypes.h" #include "lluuid.h" -#include "vorbisencode.h" +#include "llvorbisencode.h" // system libraries #include <boost/tokenizer.hpp> diff --git a/linden/indra/newview/llviewermessage.cpp b/linden/indra/newview/llviewermessage.cpp index dbf9d725e..5f333e9a4 100755 --- a/linden/indra/newview/llviewermessage.cpp +++ b/linden/indra/newview/llviewermessage.cpp @@ -37,7 +37,7 @@ #include <deque> -#include "audioengine.h" +#include "llaudioengine.h" #include "indra_constants.h" #include "lscript_byteformat.h" #include "mean_collision_data.h" @@ -150,8 +150,9 @@ #include <boost/tokenizer.hpp> #include <boost/regex.hpp> // Boost Reg Expresions -#include "hippoGridManager.h" -#include "hippoLimits.h" +#include "hippogridmanager.h" +#include "hippolimits.h" +#include "wlsettingsmanager.h" #if LL_WINDOWS // For Windows specific error handler #include "llwindebug.h" // For the invalid message handler @@ -984,7 +985,7 @@ void open_offer(const std::vector<LLUUID>& items, const std::string& from_name) LL_DEBUGS("Messaging") << "Highlighting" << item->getUUID() << LL_ENDL; //highlight item - LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO); gFocusMgr.setKeyboardFocus(focus_ctrl); } @@ -2520,6 +2521,62 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) else { LLNotifications::instance().add("TeleportOffered", args, payload); + if(binary_bucket_size) + { + char* dest = new char[binary_bucket_size]; + strncpy(dest, (char*)binary_bucket, binary_bucket_size-1); /* Flawfinder: ignore */ + dest[binary_bucket_size-1] = '\0'; + + llinfos << "IM_LURE_USER binary_bucket " << dest << llendl; + + std::string str(dest); + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("|","",boost::keep_empty_tokens); + tokenizer tokens(str, sep); + tokenizer::iterator iter = tokens.begin(); + std::string global_x_str(*iter++); + std::string global_y_str(*iter++); + std::string x_str(*iter++); + std::string y_str(*iter++); + std::string z_str(*iter++); + // skip what I think must be LookAt + if(iter != tokens.end()) + iter++; // x + if(iter != tokens.end()) + iter++; // y + if(iter != tokens.end()) + iter++; // z + std::string mat_str(""); + if(iter != tokens.end()) + mat_str.assign(*iter++); + mat_str = utf8str_trim(mat_str); + + llinfos << "IM_LURE_USER tokenized " << global_x_str << "|" << global_y_str << "|" << x_str << "|" << y_str << "|" << z_str << "|" << mat_str << llendl; + + std::istringstream gxstr(global_x_str); + int global_x; + gxstr >> global_x; + + std::istringstream gystr(global_y_str); + int global_y; + gystr >> global_y; + + std::istringstream xstr(x_str); + int x; + xstr >> x; + + std::istringstream ystr(y_str); + int y; + ystr >> y; + + std::istringstream zstr(z_str); + int z; + zstr >> z; + + llinfos << "IM_LURE_USER parsed " << global_x << "|" << global_y << "|" << x << "|" << y << "|" << z << "|" << mat_str << llendl; + + gAgent.showLureDestination(name, global_x, global_y, x, y, z, mat_str); + } } // [/RLVa:KB] //LLNotifications::instance().add("TeleportOffered", args, payload); @@ -3060,8 +3117,17 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) if (!is_muted && !is_busy) { - static BOOL* sUseChatBubbles = rebind_llcontrol<BOOL>("UseChatBubbles", &gSavedSettings, true); - visible_in_chat_bubble = *sUseChatBubbles; + + BOOL sUseChatBubbles = gSavedSettings.getBOOL("UseChatBubbles"); + if(sUseChatBubbles) + { + BOOL localChat = gSavedSettings.getBOOL("UseLocalChatWithBubbles"); + if(localChat) + sUseChatBubbles = FALSE; //Act like they arn't enabled and show it anyway + } + //Update.. + visible_in_chat_bubble = sUseChatBubbles; + ((LLVOAvatar*)chatter)->addChat(chat); } } @@ -3513,6 +3579,7 @@ void process_teleport_finish(LLMessageSystem* msg, void**) // Tell the LightShare handler that we have changed regions. WindlightMessage::resetRegion(); + WLSettingsManager::wlresetRegion(); } // stuff we have to do every time we get an AvatarInitComplete from a sim @@ -3779,6 +3846,7 @@ void process_crossed_region(LLMessageSystem* msg, void**) // Tell the LightShare handler that we have changed regions. WindlightMessage::resetRegion(); + WLSettingsManager::wlresetRegion(); } @@ -5261,11 +5329,11 @@ void mean_name_callback(const LLUUID &id, const std::string& first, const std::s return; } - static const int max_collision_list_size = 20; + static const U32 max_collision_list_size = 20; if (gMeanCollisionList.size() > max_collision_list_size) { mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - for (S32 i=0; i<max_collision_list_size; i++) iter++; + for (U32 i=0; i<max_collision_list_size; i++) iter++; for_each(iter, gMeanCollisionList.end(), DeletePointer()); gMeanCollisionList.erase(iter, gMeanCollisionList.end()); } diff --git a/linden/indra/newview/llviewernetwork.cpp b/linden/indra/newview/llviewernetwork.cpp index c1d5013c8..1cfe6654b 100644 --- a/linden/indra/newview/llviewernetwork.cpp +++ b/linden/indra/newview/llviewernetwork.cpp @@ -37,7 +37,7 @@ #include "llviewercontrol.h" #include "llstartup.h" - #include "hippoGridManager.h" + #include "hippogridmanager.h" unsigned char gMACAddress[MAC_ADDRESS_BYTES]; /* Flawfinder: ignore */ diff --git a/linden/indra/newview/llviewerobject.cpp b/linden/indra/newview/llviewerobject.cpp index 1b79cd6ce..a2be26ab9 100644 --- a/linden/indra/newview/llviewerobject.cpp +++ b/linden/indra/newview/llviewerobject.cpp @@ -34,7 +34,7 @@ #include "llviewerobject.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "imageids.h" #include "indra_constants.h" #include "llmath.h" diff --git a/linden/indra/newview/llviewerparcelmedia.cpp b/linden/indra/newview/llviewerparcelmedia.cpp index b98f418d4..d4ebbd93e 100644 --- a/linden/indra/newview/llviewerparcelmedia.cpp +++ b/linden/indra/newview/llviewerparcelmedia.cpp @@ -41,47 +41,22 @@ #include "llviewerparcelmgr.h" #include "lluuid.h" #include "message.h" +#include "llviewermediafocus.h" #include "llviewerparcelmediaautoplay.h" #include "llviewerwindow.h" #include "llfirstuse.h" +#include "llpluginclassmedia.h" // Static Variables S32 LLViewerParcelMedia::sMediaParcelLocalID = 0; LLUUID LLViewerParcelMedia::sMediaRegionID; +viewer_media_t LLViewerParcelMedia::sMediaImpl; + // Local functions bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel); -// Move this to its own file. -// helper class that tries to download a URL from a web site and calls a method -// on the Panel Land Media and to discover the MIME type -class LLMimeDiscoveryResponder : public LLHTTPClient::Responder -{ -public: - LLMimeDiscoveryResponder( ) - {} - - - - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - std::string media_type = content["content-type"].asString(); - std::string::size_type idx1 = media_type.find_first_of(";"); - std::string mime_type = media_type.substr(0, idx1); - completeAny(status, mime_type); - } - - virtual void error( U32 status, const std::string& reason ) - { - completeAny(status, "none/none"); - } - - void completeAny(U32 status, const std::string& mime_type) - { - LLViewerMedia::setMimeType(mime_type); - } -}; // static void LLViewerParcelMedia::initClass() @@ -92,6 +67,13 @@ void LLViewerParcelMedia::initClass() LLViewerParcelMediaAutoPlay::initClass(); } +//static +void LLViewerParcelMedia::cleanupClass() +{ + // This needs to be destroyed before global destructor time. + sMediaImpl = NULL; +} + ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerParcelMedia::update(LLParcel* parcel) @@ -105,6 +87,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel) { sMediaRegionID = LLUUID() ; stop() ; + LL_DEBUGS("Media") << "no agent region, bailing out." << LL_ENDL; return ; } @@ -115,64 +98,54 @@ void LLViewerParcelMedia::update(LLParcel* parcel) LLUUID regionid = gAgent.getRegion()->getRegionID(); if (parcelid != sMediaParcelLocalID || regionid != sMediaRegionID) { + LL_DEBUGS("Media") << "New parcel, parcel id = " << parcelid << ", region id = " << regionid << LL_ENDL; sMediaParcelLocalID = parcelid; sMediaRegionID = regionid; new_parcel = true; } std::string mediaUrl = std::string ( parcel->getMediaURL () ); + std::string mediaCurrentUrl = std::string( parcel->getMediaCurrentURL()); + + // First use warning + if( ! mediaUrl.empty() && gSavedSettings.getWarning("FirstStreamingVideo") ) + { + LLNotifications::instance().add("ParcelCanPlayMedia", LLSD(), LLSD(), + boost::bind(callback_play_media, _1, _2, parcel)); + return; + + } + + // if we have a current (link sharing) url, use it instead + if (mediaCurrentUrl != "" && parcel->getMediaType() == "text/html") + { + mediaUrl = mediaCurrentUrl; + } + LLStringUtil::trim(mediaUrl); + + // If no parcel media is playing, nothing left to do + if(sMediaImpl.isNull()) - // has something changed? - if ( ( LLViewerMedia::getMediaURL() != mediaUrl ) - || ( LLViewerMedia::getMediaTextureID() != parcel->getMediaID () ) ) { - bool video_was_playing = FALSE; - bool same_media_id = LLViewerMedia::getMediaTextureID() == parcel->getMediaID (); + return; + } - if (LLViewerMedia::isMediaPlaying()) + // Media is playing...has something changed? + else if (( sMediaImpl->getMediaURL() != mediaUrl ) + || ( sMediaImpl->getMediaTextureID() != parcel->getMediaID() ) + || ( sMediaImpl->getMimeType() != parcel->getMediaType() )) + { + // Only play if the media types are the same. + if(sMediaImpl->getMimeType() == parcel->getMediaType()) { - video_was_playing = TRUE; + play(parcel); } - if ( !mediaUrl.empty() && same_media_id && ! new_parcel) - { - // Someone has "changed the channel", changing the URL of a video - // you were already watching. Automatically play provided the texture ID is the same - if (video_was_playing) - { - // Poke the mime type in before calling play. - // This is necessary because in this instance we are not waiting - // for the results of a header curl. In order to change the channel - // a mime type MUST be provided. - LLViewerMedia::setMimeType(parcel->getMediaType()); - play(parcel); - } - } else { stop(); } - - // Discover the MIME type - // Disabled for the time being. Get the mime type from the parcel. - if(gSavedSettings.getBOOL("AutoMimeDiscovery")) - { - LLHTTPClient::getHeaderOnly( mediaUrl, new LLMimeDiscoveryResponder()); - } - else - { - LLViewerMedia::setMimeType(parcel->getMediaType()); - } - - // First use warning - if( gSavedSettings.getWarning("FirstStreamingVideo") ) - { - LLNotifications::instance().add("ParcelCanPlayMedia", LLSD(), LLSD(), - boost::bind(callback_play_media, _1, _2, parcel)); - - } - } } else @@ -183,7 +156,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel) /* else { - // no audio player, do a first use dialog if their is media here + // no audio player, do a first use dialog if there is media here if (parcel) { std::string mediaUrl = std::string ( parcel->getMediaURL () ); @@ -212,15 +185,57 @@ void LLViewerParcelMedia::play(LLParcel* parcel) return; std::string media_url = parcel->getMediaURL(); + std::string media_current_url = parcel->getMediaCurrentURL(); std::string mime_type = parcel->getMediaType(); LLUUID placeholder_texture_id = parcel->getMediaID(); U8 media_auto_scale = parcel->getMediaAutoScale(); U8 media_loop = parcel->getMediaLoop(); S32 media_width = parcel->getMediaWidth(); S32 media_height = parcel->getMediaHeight(); - LLViewerMedia::play(media_url, mime_type, placeholder_texture_id, - media_width, media_height, media_auto_scale, - media_loop); + + // Debug print + // LL_DEBUGS("Media") << "Play media type : " << mime_type << ", url : " << media_url << LL_ENDL; + + if(sMediaImpl) + { + // If the url and mime type are the same, call play again + if(sMediaImpl->getMediaURL() == media_url + && sMediaImpl->getMimeType() == mime_type + && sMediaImpl->getMediaTextureID() == placeholder_texture_id) + { + LL_DEBUGS("Media") << "playing with existing url " << media_url << LL_ENDL; + + sMediaImpl->play(); + } + // Else if the texture id's are the same, navigate and rediscover type + // MBW -- This causes other state from the previous parcel (texture size, autoscale, and looping) to get re-used incorrectly. + // It's also not really necessary -- just creating a new instance is fine. +// else if(sMediaImpl->getMediaTextureID() == placeholder_texture_id) +// { +// sMediaImpl->navigateTo(media_url, mime_type, true); +// } + else + { + // Since the texture id is different, we need to generate a new impl + LL_DEBUGS("Media") << "new media impl with mime type " << mime_type << ", url " << media_url << LL_ENDL; + + // Delete the old one first so they don't fight over the texture. + sMediaImpl->stop(); + + sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, + media_width, media_height, media_auto_scale, + media_loop, mime_type); + } + } + else + { + // There is no media impl, make a new one + sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, + media_width, media_height, media_auto_scale, + media_loop, mime_type); + } + + LLFirstUse::useMedia(); LLViewerParcelMediaAutoPlay::playStarted(); @@ -229,20 +244,38 @@ void LLViewerParcelMedia::play(LLParcel* parcel) // static void LLViewerParcelMedia::stop() { + if(sMediaImpl.isNull()) + { + return; + } + + // We need to remove the media HUD if it is up. + LLViewerMediaFocus::getInstance()->clearFocus(); - LLViewerMedia::stop(); + // This will kill the media instance. + sMediaImpl->stop(); + sMediaImpl = NULL; } // static void LLViewerParcelMedia::pause() { - LLViewerMedia::pause(); + if(sMediaImpl.isNull()) + { + return; + } + sMediaImpl->pause(); } // static void LLViewerParcelMedia::start() { - LLViewerMedia::start(); + if(sMediaImpl.isNull()) + { + return; + } + sMediaImpl->start(); + LLFirstUse::useMedia(); LLViewerParcelMediaAutoPlay::playStarted(); @@ -251,16 +284,41 @@ void LLViewerParcelMedia::start() // static void LLViewerParcelMedia::seek(F32 time) { - LLViewerMedia::seek(time); + if(sMediaImpl.isNull()) + { + return; + } + sMediaImpl->seek(time); } - // static -LLMediaBase::EStatus LLViewerParcelMedia::getStatus() +void LLViewerParcelMedia::focus(bool focus) { - return LLViewerMedia::getStatus(); + sMediaImpl->focus(focus); } +// static +LLViewerMediaImpl::EMediaStatus LLViewerParcelMedia::getStatus() +{ + LLViewerMediaImpl::EMediaStatus result = LLViewerMediaImpl::MEDIA_NONE; + + if(sMediaImpl.notNull() && sMediaImpl->hasMedia()) + { + result = sMediaImpl->getMediaPlugin()->getStatus(); + } + + return result; +} + +// static +std::string LLViewerParcelMedia::getMimeType() +{ + return sMediaImpl.notNull() ? sMediaImpl->getMimeType() : "none/none"; +} +viewer_media_t LLViewerParcelMedia::getParcelMedia() +{ + return sMediaImpl; +} ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg, void ** ) @@ -298,7 +356,7 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg if(( command == PARCEL_MEDIA_COMMAND_PLAY ) || ( command == PARCEL_MEDIA_COMMAND_LOOP )) { - if (LLViewerMedia::isMediaPaused()) + if (getStatus() == LLViewerMediaImpl::MEDIA_PAUSED) { start(); } @@ -318,7 +376,7 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg if (flags & (1<<PARCEL_MEDIA_COMMAND_TIME)) { - if(! LLViewerMedia::hasMedia()) + if(sMediaImpl.isNull()) { LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); play(parcel); @@ -382,6 +440,119 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void * } } } +// Static +///////////////////////////////////////////////////////////////////////////////////////// +void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url) +{ + std::string region_url = gAgent.getRegion()->getCapability("ParcelNavigateMedia"); + if (!region_url.empty()) + { + // send navigate event to sim for link sharing + LLSD body; + body["agent-id"] = gAgent.getID(); + body["local-id"] = LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID(); + body["url"] = url; + LLHTTPClient::post(region_url, body, new LLHTTPClient::Responder); + } + else + { + llwarns << "can't get ParcelNavigateMedia capability" << llendl; + } + +} + +///////////////////////////////////////////////////////////////////////////////////////// +// inherited from LLViewerMediaObserver +// virtual +void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + switch(event) + { + case MEDIA_EVENT_CONTENT_UPDATED: + { + // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CONTENT_UPDATED " << LL_ENDL; + }; + break; + + case MEDIA_EVENT_TIME_DURATION_UPDATED: + { + // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_SIZE_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_SIZE_CHANGED " << LL_ENDL; + }; + break; + + case MEDIA_EVENT_CURSOR_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_NAVIGATE_BEGIN: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN " << LL_ENDL; + }; + break; + + case MEDIA_EVENT_NAVIGATE_COMPLETE: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_PROGRESS_UPDATED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << LL_ENDL; + }; + break; + + case MEDIA_EVENT_STATUS_TEXT_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_LOCATION_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_CLICK_LINK_HREF: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_PLUGIN_FAILED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL; + }; + break; + + case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << LL_ENDL; + }; + break; + + case MEDIA_EVENT_NAME_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAME_CHANGED" << LL_ENDL; + }; + break; + }; +} bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel) { @@ -399,3 +570,19 @@ bool callback_play_media(const LLSD& notification, const LLSD& response, LLParce return false; } +// TODO: observer +/* +void LLViewerParcelMediaNavigationObserver::onNavigateComplete( const EventType& event_in ) +{ + std::string url = event_in.getStringValue(); + + if (mCurrentURL != url && ! mFromMessage) + { + LLViewerParcelMedia::sendMediaNavigateMessage(url); + } + + mCurrentURL = url; + mFromMessage = false; + +} +*/ diff --git a/linden/indra/newview/llviewerparcelmedia.h b/linden/indra/newview/llviewerparcelmedia.h index 18988704d..0f1e85c78 100644 --- a/linden/indra/newview/llviewerparcelmedia.h +++ b/linden/indra/newview/llviewerparcelmedia.h @@ -33,18 +33,22 @@ #ifndef LLVIEWERPARCELMEDIA_H #define LLVIEWERPARCELMEDIA_H -#include "llmediabase.h" +#include "llviewermedia.h" class LLMessageSystem; class LLParcel; +class LLViewerParcelMediaNavigationObserver; + // This class understands land parcels, network traffic, LSL media // transport commands, and talks to the LLViewerMedia class to actually // do playback. It allows us to remove code from LLViewerParcelMgr. -class LLViewerParcelMedia +class LLViewerParcelMedia : public LLViewerMediaObserver { + LOG_CLASS(LLViewerParcelMedia); public: static void initClass(); + static void cleanupClass(); static void update(LLParcel* parcel); // called when the agent's parcel has a new URL, or the agent has @@ -60,17 +64,38 @@ class LLViewerParcelMedia static void start(); // restart after pause - no need for all the setup + static void focus(bool focus); + static void seek(F32 time); // jump to timecode time - static LLMediaBase::EStatus getStatus(); + static LLViewerMediaImpl::EMediaStatus getStatus(); + static std::string getMimeType(); + static viewer_media_t getParcelMedia(); static void processParcelMediaCommandMessage( LLMessageSystem *msg, void ** ); static void processParcelMediaUpdate( LLMessageSystem *msg, void ** ); + static void sendMediaNavigateMessage(const std::string& url); + + // inherited from LLViewerMediaObserver + virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); public: static S32 sMediaParcelLocalID; static LLUUID sMediaRegionID; + // HACK: this will change with Media on a Prim + static viewer_media_t sMediaImpl; +}; + + +class LLViewerParcelMediaNavigationObserver +{ +public: + std::string mCurrentURL; + bool mFromMessage; + + // void onNavigateComplete( const EventType& event_in ); + }; #endif diff --git a/linden/indra/newview/llviewerparcelmediaautoplay.cpp b/linden/indra/newview/llviewerparcelmediaautoplay.cpp index dbb9c3200..ccd6b14d3 100644 --- a/linden/indra/newview/llviewerparcelmediaautoplay.cpp +++ b/linden/indra/newview/llviewerparcelmediaautoplay.cpp @@ -109,7 +109,7 @@ BOOL LLViewerParcelMediaAutoPlay::tick() if ((!mPlayed) && // if we've never played (mTimeInParcel > AUTOPLAY_TIME) && // and if we've been here for so many seconds (this_media_url.size() != 0) && // and if the parcel has media - (!LLViewerMedia::isMediaPlaying())) // and if the media is not already playing + (LLViewerParcelMedia::sMediaImpl.isNull())) // and if the media is not already playing { if (this_media_texture_id.notNull()) // and if the media texture is good { diff --git a/linden/indra/newview/llviewerparcelmediaautoplay.h b/linden/indra/newview/llviewerparcelmediaautoplay.h index cc2e70b1b..16279e7f1 100644 --- a/linden/indra/newview/llviewerparcelmediaautoplay.h +++ b/linden/indra/newview/llviewerparcelmediaautoplay.h @@ -33,7 +33,6 @@ #ifndef LLVIEWERPARCELMEDIAAUTOPLAY_H #define LLVIEWERPARCELMEDIAAUTOPLAY_H -#include "llmediabase.h" #include "lltimer.h" // timer to automatically play media diff --git a/linden/indra/newview/llviewerparcelmgr.cpp b/linden/indra/newview/llviewerparcelmgr.cpp index 257ce0d26..b589f2e24 100644 --- a/linden/indra/newview/llviewerparcelmgr.cpp +++ b/linden/indra/newview/llviewerparcelmgr.cpp @@ -35,7 +35,7 @@ #include "llviewerparcelmgr.h" // Library includes -#include "audioengine.h" +#include "llaudioengine.h" #include "indra_constants.h" #include "llcachename.h" #include "llgl.h" @@ -70,7 +70,7 @@ #include "roles_constants.h" #include "llweb.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" const F32 PARCEL_COLLISION_DRAW_SECS = 1.f; @@ -1605,6 +1605,9 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use // Request access list information for this land LLViewerParcelMgr::getInstance()->sendParcelAccessListRequest(AL_ACCESS | AL_BAN); + // Request the media url filter list for this land + LLViewerParcelMgr::getInstance()->requestParcelMediaURLFilter(); + // Request dwell for this land, if it's not public land. LLViewerParcelMgr::getInstance()->mSelectedDwell = 0.f; if (0 != local_id) @@ -1732,21 +1735,6 @@ void optionally_start_music(const std::string& music_url) } } - -void callback_start_music(S32 option, void* data) -{ - if (option == 0) - { - // Before the callback, we verified the url was good. - // We fetch again to avoid lag while loading. - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - gAudiop->startInternetStream(parcel->getMusicURL()); - - LLOverlayBar::musicFirstRun(); - } - gSavedSettings.setWarning("FirstStreamingMusic", FALSE); -} - // static void LLViewerParcelMgr::processParcelAccessListReply(LLMessageSystem *msg, void **user) { @@ -1943,6 +1931,66 @@ void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which) } } +class LLParcelMediaURLFilterResponder : public LLHTTPClient::Responder +{ + virtual void result(const LLSD& content) + { + LLViewerParcelMgr::getInstance()->receiveParcelMediaURLFilter(content); + } +}; + +void LLViewerParcelMgr::requestParcelMediaURLFilter() +{ + if (!mSelected) + { + return; + } + + LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); + if (!region) + { + return; + } + + LLParcel* parcel = mCurrentParcel; + if (!parcel) + { + llwarns << "no parcel" << llendl; + return; + } + + LLSD body; + body["local-id"] = parcel->getLocalID(); + body["list"] = parcel->getMediaURLFilterList(); + + std::string url = region->getCapability("ParcelMediaURLFilterList"); + if (!url.empty()) + { + LLHTTPClient::post(url, body, new LLParcelMediaURLFilterResponder); + } + else + { + llwarns << "can't get ParcelMediaURLFilterList cap" << llendl; + } +} + + +void LLViewerParcelMgr::receiveParcelMediaURLFilter(const LLSD &content) +{ + if (content.has("list")) + { + LLParcel* parcel = LLViewerParcelMgr::getInstance()->mCurrentParcel; + if (!parcel) return; + + if (content["local-id"].asInteger() == parcel->getLocalID()) + { + parcel->setMediaURLFilterList(content["list"]); + + LLViewerParcelMgr::getInstance()->notifyObservers(); + } + } +} + void LLViewerParcelMgr::deedLandToGroup() { diff --git a/linden/indra/newview/llviewerparcelmgr.h b/linden/indra/newview/llviewerparcelmgr.h index 9f762a186..9bf609639 100644 --- a/linden/indra/newview/llviewerparcelmgr.h +++ b/linden/indra/newview/llviewerparcelmgr.h @@ -198,6 +198,11 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr> // Takes an Access List flag, like AL_ACCESS or AL_BAN void sendParcelAccessListRequest(U32 flags); + // asks for the parcel's media url filter list + void requestParcelMediaURLFilter(); + // receive the response + void receiveParcelMediaURLFilter(const LLSD &content); + // Dwell is not part of the usual parcel update information because the // simulator doesn't actually know the per-parcel dwell. Ack! We have // to get it out of the database. diff --git a/linden/indra/newview/llviewerprecompiledheaders.h b/linden/indra/newview/llviewerprecompiledheaders.h index 9bc6574f0..a0b99bf2f 100644 --- a/linden/indra/newview/llviewerprecompiledheaders.h +++ b/linden/indra/newview/llviewerprecompiledheaders.h @@ -165,7 +165,7 @@ #include "llinstantmessage.h" #include "llinvite.h" //#include "llloginflags.h" -#include "llmail.h" +//#include "llmail.h" #include "llmessagethrottle.h" #include "llnamevalue.h" #include "llpacketack.h" diff --git a/linden/indra/newview/llviewerregion.cpp b/linden/indra/newview/llviewerregion.cpp index 4fd3bfb61..d93c425bb 100644 --- a/linden/indra/newview/llviewerregion.cpp +++ b/linden/indra/newview/llviewerregion.cpp @@ -323,7 +323,7 @@ void LLViewerRegion::loadCache() LLUUID cache_id; nread = fread(&cache_id.mData, 1, UUID_BYTES, fp); - if (nread != UUID_BYTES || mCacheID != cache_id) + if (nread != (size_t)UUID_BYTES || mCacheID != cache_id) { llinfos << "Cache ID doesn't match for this region, discarding" << llendl; @@ -399,7 +399,7 @@ void LLViewerRegion::saveCache() } // write the cache id for this sim - if (fwrite(&mCacheID.mData, 1, UUID_BYTES, fp) != UUID_BYTES) + if (fwrite(&mCacheID.mData, 1, UUID_BYTES, fp) != (size_t)UUID_BYTES) { llwarns << "Short write" << llendl; } @@ -452,6 +452,12 @@ void LLViewerRegion::setWaterHeight(F32 water_level) mLandp->setWaterHeight(water_level); } + +void LLViewerRegion::rebuildWater() +{ + mLandp->rebuildWater(); +} + F32 LLViewerRegion::getWaterHeight() const { return mLandp->getWaterHeight(); @@ -1416,7 +1422,10 @@ void LLViewerRegion::setSeedCapability(const std::string& url) LLSD capabilityNames = LLSD::emptyArray(); capabilityNames.append("ChatSessionRequest"); capabilityNames.append("CopyInventoryFromNotecard"); + // Aurora settings -- MC + capabilityNames.append("DispatchOpenRegionSettings"); capabilityNames.append("DispatchRegionInfo"); + capabilityNames.append("DispatchWindLightSettings"); capabilityNames.append("EstateChangeInfo"); capabilityNames.append("EventQueueGet"); capabilityNames.append("FetchInventory"); @@ -1429,11 +1438,14 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("MapLayerGod"); capabilityNames.append("NewFileAgentInventory"); capabilityNames.append("ParcelPropertiesUpdate"); + capabilityNames.append("ParcelMediaURLFilterList"); + capabilityNames.append("ParcelNavigateMedia"); capabilityNames.append("ParcelVoiceInfoRequest"); capabilityNames.append("ProductInfoRequest"); capabilityNames.append("ProvisionVoiceAccountRequest"); capabilityNames.append("RemoteParcelRequest"); capabilityNames.append("RequestTextureDownload"); + capabilityNames.append("RetrieveWindLightSettings"); capabilityNames.append("SearchStatRequest"); capabilityNames.append("SearchStatTracking"); capabilityNames.append("SendPostcard"); diff --git a/linden/indra/newview/llviewerregion.h b/linden/indra/newview/llviewerregion.h index 09280a53f..8cc80e3cf 100644 --- a/linden/indra/newview/llviewerregion.h +++ b/linden/indra/newview/llviewerregion.h @@ -132,6 +132,7 @@ class LLViewerRegion void setWaterHeight(F32 water_level); F32 getWaterHeight() const; + void rebuildWater(); BOOL isVoiceEnabled() const; @@ -315,10 +316,11 @@ class LLViewerRegion LLDynamicArray<U32> mMapAvatars; LLDynamicArray<LLUUID> mMapAvatarIDs; -private: // The surfaces and other layers LLSurface* mLandp; +private: + // Region geometry data LLVector3d mOriginGlobal; // Location of southwest corner of region (meters) LLVector3d mCenterGlobal; // Location of center in world space (meters) diff --git a/linden/indra/newview/llviewertexteditor.cpp b/linden/indra/newview/llviewertexteditor.cpp index 1616b9720..5d0656d3f 100644 --- a/linden/indra/newview/llviewertexteditor.cpp +++ b/linden/indra/newview/llviewertexteditor.cpp @@ -33,7 +33,7 @@ #include "llviewerprecompiledheaders.h" #include "llfocusmgr.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llagent.h" #include "llinventory.h" #include "llinventorymodel.h" diff --git a/linden/indra/newview/llviewerwindow.cpp b/linden/indra/newview/llviewerwindow.cpp index 401e62de1..920d42e41 100644 --- a/linden/indra/newview/llviewerwindow.cpp +++ b/linden/indra/newview/llviewerwindow.cpp @@ -54,7 +54,7 @@ // // linden library includes -#include "audioengine.h" // mute on minimize +#include "llaudioengine.h" // mute on minimize #include "indra_constants.h" #include "llassetstorage.h" #include "llfontgl.h" @@ -156,7 +156,6 @@ #include "lltoolselectland.h" #include "lltoolview.h" #include "lluictrlfactory.h" -#include "lluploaddialog.h" #include "llurldispatcher.h" // SLURL from other app instance #include "llvieweraudio.h" #include "llviewercamera.h" @@ -164,6 +163,8 @@ #include "llviewerimagelist.h" #include "llviewerinventory.h" #include "llviewerkeyboard.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h" #include "llviewermenu.h" #include "llviewermessage.h" #include "llviewerobjectlist.h" @@ -316,7 +317,9 @@ class LLDebugText S32 hours = (S32)(time / (60*60)); S32 mins = (S32)((time - hours*(60*60)) / 60); S32 secs = (S32)((time - hours*(60*60) - mins*60)); - addText(xpos, ypos, llformat(" Debug %d: %d:%02d:%02d", idx, hours,mins,secs)); ypos += y_inc2; + std::string label = gDebugTimerLabel[idx]; + if (label.empty()) label = llformat("Debug: %d", idx); + addText(xpos, ypos, llformat(" %s: %d:%02d:%02d", label.c_str(), hours,mins,secs)); ypos += y_inc2; } F32 time = gFrameTimeSeconds; @@ -803,6 +806,7 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK if (handle) return handle; + // *HACK: this should be rolled into the composite tool logic, not // hardcoded at the top level. if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance()) @@ -1149,7 +1153,7 @@ void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data) case SLURL_MESSAGE_TYPE: // received URL std::string url = (const char*)data; - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; if (LLURLDispatcher::dispatch(url, web, trusted_browser)) { @@ -1672,9 +1676,64 @@ void LLViewerWindow::initWorldUI() gHoverView = new LLHoverView(std::string("gHoverView"), full_window); gHoverView->setVisible(TRUE); mRootView->addChild(gHoverView); - + gIMMgr = LLIMMgr::getInstance(); + // Make sure we only create menus once per session -- MC + if (!gMenuHolder) + { + init_menus(); + } + + // Toolbox floater + if (!gFloaterTools) + { + gFloaterTools = new LLFloaterTools(); + gFloaterTools->setVisible(FALSE); + } + + if ( gHUDView == NULL ) + { + LLRect hud_rect = full_window; + hud_rect.mBottom += 50; + if (gMenuBarView) + { + hud_rect.mTop -= gMenuBarView->getRect().getHeight(); + } + gHUDView = new LLHUDView(hud_rect); + // put behind everything else in the UI + mRootView->addChildAtEnd(gHUDView); + } +} + +// initWorldUI that wasn't before logging in. Some of this may require the access the 'LindenUserDir'. +void LLViewerWindow::initWorldUI_postLogin() +{ + S32 height = mRootView->getRect().getHeight(); + S32 width = mRootView->getRect().getWidth(); + LLRect full_window(0, height, width, 0); + + // The status base must be created before calling sendChildToFront below, + // or the text of the menu (after logging in) won't be visible. + if (!gStatusBar) + { + // Status bar + S32 menu_bar_height = gMenuBarView->getRect().getHeight(); + LLRect root_rect = mRootView->getRect(); + LLRect status_rect(0, root_rect.getHeight(), root_rect.getWidth(), root_rect.getHeight() - menu_bar_height); + gStatusBar = new LLStatusBar(std::string("status"), status_rect); + gStatusBar->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); + + gStatusBar->reshape(root_rect.getWidth(), gStatusBar->getRect().getHeight(), TRUE); + gStatusBar->translate(0, root_rect.getHeight() - gStatusBar->getRect().getHeight()); + // sync bg color with menu bar + gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor() ); + mRootView->addChild(gStatusBar); + } + + // Menu holder appears on top to get first pass at all mouse events + mRootView->sendChildToFront(gMenuHolder); + if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) { LLFloaterChat::getInstance(LLSD())->loadHistory(); @@ -1690,8 +1749,6 @@ void LLViewerWindow::initWorldUI() mRootView->addChild(gMorphView); gMorphView->setVisible(FALSE); - // *Note: this is where gFloaterMute used to be initialized. - LLWorldMapView::initClass(); adjust_rect_centered_partial_zoom("FloaterWorldMapRect2", full_window); @@ -1709,46 +1766,7 @@ void LLViewerWindow::initWorldUI() gFloaterTeleportHistory->setVisible(FALSE); } - // - // Tools for building - // - - // Toolbox floater - - // Make sure we only create menus once per session -- MC - if (!gMenuHolder) - { - init_menus(); - } - - if (!gFloaterTools) - { - gFloaterTools = new LLFloaterTools(); - gFloaterTools->setVisible(FALSE); - } - - if (!gStatusBar) - { - // Status bar - S32 menu_bar_height = gMenuBarView->getRect().getHeight(); - LLRect root_rect = mRootView->getRect(); - LLRect status_rect(0, root_rect.getHeight(), root_rect.getWidth(), root_rect.getHeight() - menu_bar_height); - gStatusBar = new LLStatusBar(std::string("status"), status_rect); - gStatusBar->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); - - gStatusBar->reshape(root_rect.getWidth(), gStatusBar->getRect().getHeight(), TRUE); - gStatusBar->translate(0, root_rect.getHeight() - gStatusBar->getRect().getHeight()); - // sync bg color with menu bar - gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor() ); - mRootView->addChild(gStatusBar); - } - LLFloaterChatterBox::createInstance(LLSD()); - - - // menu holder appears on top to get first pass at all mouse events - - mRootView->sendChildToFront(gMenuHolder); } // Destroy the UI @@ -2195,7 +2213,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) if (key < 0x80) { // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first. - return gFocusMgr.childHasKeyboardFocus(mRootView); + return (gFocusMgr.getKeyboardFocus() != NULL); } } @@ -2258,7 +2276,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) } // Traverses up the hierarchy - LLUICtrl* keyboard_focus = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); if( keyboard_focus ) { // arrow keys move avatar while chatting hack @@ -2392,7 +2410,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask) } // Traverses up the hierarchy - LLView* keyboard_focus = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); if( keyboard_focus ) { if (keyboard_focus->handleUnicodeChar(uni_char, FALSE)) @@ -2547,7 +2565,7 @@ BOOL LLViewerWindow::handlePerFrameHover() } // clean up current focus - LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus(); + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); if (cur_focus) { if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain()) @@ -2804,7 +2822,7 @@ BOOL LLViewerWindow::handlePerFrameHover() // snap floaters to top of chat bar/button strip LLView* chatbar_and_buttons = gOverlayBar->getChild<LLView>("chatbar_and_buttons", TRUE); // find top of chatbar and state buttons, if either are visible - if (chatbar_and_buttons && !chatbar_and_buttons->getLocalBoundingRect().isNull()) + if (chatbar_and_buttons && !chatbar_and_buttons->getLocalBoundingRect().isEmpty()) { // convert top/left corner of chatbar/buttons container to gFloaterView-relative coordinates S32 top, left; @@ -2930,12 +2948,18 @@ BOOL LLViewerWindow::handlePerFrameHover() { do_pick = FALSE; } + + if(LLViewerMediaFocus::getInstance()->getFocus()) + { + // When in-world media is in focus, pick every frame so that browser mouse-overs, dragging scrollbars, etc. work properly. + do_pick = TRUE; + } if (do_pick) { mouse_moved_since_pick = FALSE; mPickTimer.reset(); - pickAsync(getCurrentMouseX(), getCurrentMouseY(), mask, hoverPickCallback, TRUE); + pickAsync(getCurrentMouseX(), getCurrentMouseY(), mask, hoverPickCallback, TRUE, TRUE); } previous_x = x; @@ -4738,7 +4762,7 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, BOOL result_first_try = FALSE; BOOL result_second_try = FALSE; - LLUICtrl* keyboard_focus = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); send_agent_pause(); llinfos << "Stopping GL during changeDisplaySettings" << llendl; stopGL(); @@ -4967,7 +4991,6 @@ LLBottomPanel::LLBottomPanel(const LLRect &rect) : mFactoryMap["toolbar"] = LLCallbackMap(createToolBar, NULL); mFactoryMap["overlay"] = LLCallbackMap(createOverlayBar, NULL); - mFactoryMap["hud"] = LLCallbackMap(createHUD, NULL); LLUICtrlFactory::getInstance()->buildPanel(this, "panel_bars.xml", &getFactoryMap()); setOrigin(rect.mLeft, rect.mBottom); @@ -4990,12 +5013,6 @@ void LLBottomPanel::draw() LLPanel::draw(); } -void* LLBottomPanel::createHUD(void* data) -{ - gHUDView = new LLHUDView(); - return gHUDView; -} - void* LLBottomPanel::createOverlayBar(void* data) { @@ -5208,12 +5225,8 @@ void LLPickInfo::updateXYCoords() LLPointer<LLViewerImage> imagep = gImageList.getImage(tep->getID()); if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull()) { - LLCoordGL coords; - - coords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth()); - coords.mY = llround(mUVCoords.mV[VY] * (F32)imagep->getHeight()); - - gViewerWindow->getWindow()->convertCoords(coords, &mXYCoords); + mXYCoords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth()); + mXYCoords.mY = llround((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight()); } } } diff --git a/linden/indra/newview/llviewerwindow.h b/linden/indra/newview/llviewerwindow.h index 85cdc5221..d26d82010 100644 --- a/linden/indra/newview/llviewerwindow.h +++ b/linden/indra/newview/llviewerwindow.h @@ -144,6 +144,7 @@ class LLViewerWindow : public LLWindowCallbacks void adjustRectanglesForFirstUse(const LLRect& window); void adjustControlRectanglesForFirstUse(const LLRect& window); void initWorldUI(); + void initWorldUI_postLogin(); // // LLWindowCallback interface implementation diff --git a/linden/indra/newview/llvoavatar.cpp b/linden/indra/newview/llvoavatar.cpp index 7bbaf489c..3067368cd 100644 --- a/linden/indra/newview/llvoavatar.cpp +++ b/linden/indra/newview/llvoavatar.cpp @@ -37,7 +37,7 @@ #include <stdio.h> #include <ctype.h> -#include "audioengine.h" +#include "llaudioengine.h" #include "noise.h" #include "llagent.h" // Get state values from here @@ -69,6 +69,7 @@ #include "lltoolmorph.h" #include "llviewercamera.h" #include "llviewerimagelist.h" +#include "llviewermedia.h" #include "llviewermenu.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" @@ -93,8 +94,8 @@ #else #include "boost/lexical_cast.hpp" #endif -#include "hippoLimits.h"// getMaxPrimScale - +#include "hippolimits.h"// getMaxPrimScale +#include "llstartup.h" // [RLVa:KB] #include "rlvhandler.h" // [/RLVa:KB] @@ -2038,7 +2039,8 @@ void LLVOAvatar::buildCharacter() //------------------------------------------------------------------------- // build the attach and detach menus //------------------------------------------------------------------------- - if (mIsSelf) + // MoonWorld: gAttachPieMenu is no more. + if (gAttachPieMenu && mIsSelf) { // *TODO: Translate gAttachBodyPartPieMenus[0] = NULL; @@ -2157,7 +2159,8 @@ void LLVOAvatar::buildCharacter() } } - for (S32 pass = 0; pass < 2; pass++) + // MoonWorld: gAttachSubMenu is gone! + for (S32 pass = 0; gAttachSubMenu && pass < 2; pass++) { for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ) @@ -3666,7 +3669,6 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) } // [/RLVa:KB] - BOOL need_comma = FALSE; static BOOL* sShowClientNameTag = rebind_llcontrol<BOOL>("ShowClientNameTag", &gSavedSettings, true); @@ -3844,6 +3846,18 @@ void LLVOAvatar::idleUpdateTractorBeam() { return; } + const LLPickInfo& pick = gViewerWindow->getLastPick(); + + // No beam for media textures + // TODO: this will change for Media on a Prim + if(pick.getObject() && pick.mObjectFace >= 0) + { + const LLTextureEntry* tep = pick.getObject()->getTE(pick.mObjectFace); + if (tep && LLViewerMedia::textureHasMedia(tep->getID())) + { + return; + } + } // This is only done for yourself (maybe it should be in the agent?) if (!needsRenderBeam() || !mIsBuilt) @@ -3954,7 +3968,7 @@ void LLVOAvatar::idleUpdateTractorBeam() } else { - const LLPickInfo& pick = gViewerWindow->getLastPick(); + mBeam->setPositionGlobal(pick.mPosGlobal); } @@ -5129,12 +5143,6 @@ void LLVOAvatar::updateTextures() if (texture_dict->mIsLocalTexture) { addLocalTextureStats((ETextureIndex)index, imagep, texel_area_ratio, render_avatar, layer_baked[baked_index]); - // SNOW-8 : temporary snowglobe1.0 fix for baked textures - if (render_avatar && !gGLManager.mIsDisabled ) - { - // bind the texture so that its boost level won't be slammed - gGL.getTexUnit(0)->bind(imagep); - } } else if (texture_dict->mIsBakedTexture) { @@ -5171,8 +5179,14 @@ void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerImage* imagep, F32 desired_pixels; if( mIsSelf ) { - desired_pixels = llmin(mPixelArea, (F32)TEX_IMAGE_AREA_SELF ); + desired_pixels = llmax(mPixelArea, (F32)TEX_IMAGE_AREA_SELF ); imagep->setBoostLevel(LLViewerImageBoostLevel::BOOST_AVATAR_SELF); + // SNOW-8 : temporary snowglobe1.0 fix for baked textures + if (render_avatar && !gGLManager.mIsDisabled ) + { + // bind the texture so that its boost level won't be slammed + gGL.getTexUnit(0)->bind(imagep); + } } else { @@ -5478,6 +5492,15 @@ void LLVOAvatar::resetAnimations() //----------------------------------------------------------------------------- BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) { + // [Ansariel Hiller]: Disable pesky hover up animation that changes + // hand and finger position and often breaks correct + // fit of prim nails, rings etc. when flying and + // using an AO. + if ("62c5de58-cb33-5743-3d07-9e4cd4352864" == id.getString() && gSavedSettings.getBOOL("DisableInternalFlyUpAnimation")) + { + return TRUE; + } + LLMemType mt(LLMemType::MTYPE_AVATAR); // start special case female walk for female avatars @@ -7447,8 +7470,7 @@ LLGLuint LLVOAvatar::getScratchTexName( LLGLenum format, U32* texture_bytes ) { case GL_LUMINANCE: components = 1; internal_format = GL_LUMINANCE8; break; case GL_ALPHA: components = 1; internal_format = GL_ALPHA8; break; -// Deprecated. See http://svn.secondlife.com/trac/linden/changeset/2757 -// case GL_COLOR_INDEX: components = 1; internal_format = GL_COLOR_INDEX8_EXT; break; + case GL_COLOR_INDEX: components = 1; internal_format = GL_COLOR_INDEX8_EXT; break; case GL_LUMINANCE_ALPHA: components = 2; internal_format = GL_LUMINANCE8_ALPHA8; break; case GL_RGB: components = 3; internal_format = GL_RGB8; break; case GL_RGBA: components = 4; internal_format = GL_RGBA8; break; diff --git a/linden/indra/newview/llvoavatar.h b/linden/indra/newview/llvoavatar.h index 50ce53a7a..548818dc8 100644 --- a/linden/indra/newview/llvoavatar.h +++ b/linden/indra/newview/llvoavatar.h @@ -148,6 +148,7 @@ class LLVOAvatar : void clampAttachmentPositions(); S32 getAttachmentCount(); // Warning: order(N) not order(1) + // HUD functions BOOL hasHUDAttachment() const; LLBBox getHUDBBox() const; diff --git a/linden/indra/newview/llvograss.cpp b/linden/indra/newview/llvograss.cpp index f73887226..913ec3386 100644 --- a/linden/indra/newview/llvograss.cpp +++ b/linden/indra/newview/llvograss.cpp @@ -48,6 +48,7 @@ #include "llviewercamera.h" #include "llviewerimagelist.h" #include "llviewerregion.h" +#include "llselectmgr.h" #include "pipeline.h" #include "llspatialpartition.h" #include "llworld.h" @@ -721,3 +722,93 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en return ret; } +void LLVOGrass::generateSilhouetteVertices(std::vector<LLVector3> &vertices, + std::vector<LLVector3> &normals, + std::vector<S32> &segments, + const LLVector3& obj_cam_vec, + const LLMatrix4& mat, + const LLMatrix3& norm_mat) +{ + vertices.clear(); + normals.clear(); + segments.clear(); + + F32 width = sSpeciesTable[mSpecies]->mBladeSizeX; + F32 height = sSpeciesTable[mSpecies]->mBladeSizeY; + + for (S32 i = 0; i < mNumBlades; i++) + { + F32 x = exp_x[i] * mScale.mV[VX]; + F32 y = exp_y[i] * mScale.mV[VY]; + F32 xf = rot_x[i] * GRASS_BLADE_BASE * width * w_mod[i]; + F32 yf = rot_y[i] * GRASS_BLADE_BASE * width * w_mod[i]; + F32 dzx = dz_x [i]; + F32 dzy = dz_y [i]; + + F32 blade_height= GRASS_BLADE_HEIGHT * height * w_mod[i]; + + LLVector3 position1; + + position1.mV[0] = mPosition.mV[VX] + x + xf; + position1.mV[1] = mPosition.mV[VY] + y + yf; + position1.mV[2] = mRegionp->getLand().resolveHeightRegion(position1); + + LLVector3 position2 = position1; + + position2.mV[0] += dzx; + position2.mV[1] += dzy; + position2.mV[2] += blade_height; + + LLVector3 position3; + + position3.mV[0] = mPosition.mV[VX] + x - xf; + position3.mV[1] = mPosition.mV[VY] + y - xf; + position3.mV[2] = mRegionp->getLand().resolveHeightRegion(position3); + + LLVector3 position4 = position3; + + position4.mV[0] += dzx; + position4.mV[1] += dzy; + position4.mV[2] += blade_height; + + + LLVector3 normal = (position1-position2) % (position2 - position3); + normal.normalize(); + + vertices.push_back(position1 + mRegionp->getOriginAgent()); + normals.push_back(normal); + vertices.push_back(position2 + mRegionp->getOriginAgent()); + normals.push_back(normal); + segments.push_back(vertices.size()); + + vertices.push_back(position2 + mRegionp->getOriginAgent()); + normals.push_back(normal); + vertices.push_back(position4 + mRegionp->getOriginAgent()); + normals.push_back(normal); + segments.push_back(vertices.size()); + + vertices.push_back(position4 + mRegionp->getOriginAgent()); + normals.push_back(normal); + vertices.push_back(position3 + mRegionp->getOriginAgent()); + normals.push_back(normal); + segments.push_back(vertices.size()); + + vertices.push_back(position3 + mRegionp->getOriginAgent()); + normals.push_back(normal); + vertices.push_back(position1 + mRegionp->getOriginAgent()); + normals.push_back(normal); + segments.push_back(vertices.size()); + } +} + + + +void LLVOGrass::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point) +{ + generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, + nodep->mSilhouetteSegments, + LLVector3(0,0,0), LLMatrix4(), LLMatrix3()); + + nodep->mSilhouetteExists = TRUE; + +} diff --git a/linden/indra/newview/llvograss.h b/linden/indra/newview/llvograss.h index 25fa04cad..c76ab9357 100644 --- a/linden/indra/newview/llvograss.h +++ b/linden/indra/newview/llvograss.h @@ -37,6 +37,7 @@ #include "lldarray.h" #include <map> +class LLSelectNode; class LLSurfacePatch; class LLViewerImage; @@ -76,6 +77,8 @@ class LLVOGrass : public LLAlphaObject /*virtual*/ BOOL updateLOD(); /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area + void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point); + void plantBlades(); /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. @@ -125,6 +128,12 @@ class LLVOGrass : public LLAlphaObject ~LLVOGrass(); private: + void generateSilhouetteVertices(std::vector<LLVector3> &vertices, + std::vector<LLVector3> &normals, + std::vector<S32> &segments, + const LLVector3& view_vec, + const LLMatrix4& mat, + const LLMatrix3& norm_mat); void updateSpecies(); F32 mLastHeight; // For cheap update hack S32 mNumBlades; diff --git a/linden/indra/newview/llvoiceclient.cpp b/linden/indra/newview/llvoiceclient.cpp index d67b9e3a2..7b1ed954d 100644 --- a/linden/indra/newview/llvoiceclient.cpp +++ b/linden/indra/newview/llvoiceclient.cpp @@ -1795,7 +1795,7 @@ void LLVoiceClient::stateMachine() if(!mSocket) { - mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); + mSocket = LLSocket::create(LLSocket::STREAM_TCP); } mConnected = mSocket->blockingConnect(mDaemonHost); diff --git a/linden/indra/newview/llvotree.cpp b/linden/indra/newview/llvotree.cpp index 6a59253a9..8c6abdcc4 100644 --- a/linden/indra/newview/llvotree.cpp +++ b/linden/indra/newview/llvotree.cpp @@ -47,6 +47,7 @@ #include "llagent.h" #include "lldrawable.h" #include "llface.h" +#include "llselectmgr.h" #include "llviewercamera.h" #include "llviewerimagelist.h" #include "llviewerobjectlist.h" @@ -1327,3 +1328,127 @@ LLTreePartition::LLTreePartition() mLODPeriod = 1; } + + +void LLVOTree::generateSilhouetteVertices(std::vector<LLVector3> &vertices, + std::vector<LLVector3> &normals, + std::vector<S32> &segments, + const LLVector3& obj_cam_vec, + const LLMatrix4& local_matrix, + const LLMatrix3& normal_matrix) +{ + vertices.clear(); + normals.clear(); + segments.clear(); + + F32 height = mBillboardScale; // *mBillboardRatio * 0.5; + F32 width = height * mTrunkAspect; + + LLVector3 position1 = LLVector3(-width * 0.5,0,0) * local_matrix; + LLVector3 position2 = LLVector3(-width * 0.5,0,height) * local_matrix; + LLVector3 position3 = LLVector3(+width * 0.5,0,height) * local_matrix; + LLVector3 position4 = LLVector3(+width * 0.5,0,0) * local_matrix; + + LLVector3 position5 = LLVector3(0,-width * 0.5,0) * local_matrix; + LLVector3 position6 = LLVector3(0,-width * 0.5,height) * local_matrix; + LLVector3 position7 = LLVector3(0,+width * 0.5,height) * local_matrix; + LLVector3 position8 = LLVector3(0,+width * 0.5,0) * local_matrix; + + + LLVector3 normal = (position1-position2) % (position2-position3); + normal.normalize(); + + vertices.push_back(position1); + normals.push_back(normal); + vertices.push_back(position2); + normals.push_back(normal); + segments.push_back(vertices.size()); + + vertices.push_back(position2); + normals.push_back(normal); + vertices.push_back(position3); + normals.push_back(normal); + segments.push_back(vertices.size()); + + vertices.push_back(position3); + normals.push_back(normal); + vertices.push_back(position4); + normals.push_back(normal); + segments.push_back(vertices.size()); + + vertices.push_back(position4); + normals.push_back(normal); + vertices.push_back(position1); + normals.push_back(normal); + segments.push_back(vertices.size()); + + normal = (position5-position6) % (position6-position7); + normal.normalize(); + + vertices.push_back(position5); + normals.push_back(normal); + vertices.push_back(position6); + normals.push_back(normal); + segments.push_back(vertices.size()); + + vertices.push_back(position6); + normals.push_back(normal); + vertices.push_back(position7); + normals.push_back(normal); + segments.push_back(vertices.size()); + + vertices.push_back(position7); + normals.push_back(normal); + vertices.push_back(position8); + normals.push_back(normal); + segments.push_back(vertices.size()); + + vertices.push_back(position8); + normals.push_back(normal); + vertices.push_back(position5); + normals.push_back(normal); + segments.push_back(vertices.size()); + +} + + +void LLVOTree::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point) +{ + LLVector3 position; + LLQuaternion rotation; + + if (mDrawable->isActive()) + { + if (mDrawable->isSpatialRoot()) + { + position = LLVector3(); + rotation = LLQuaternion(); + } + else + { + position = mDrawable->getPosition(); + rotation = mDrawable->getRotation(); + } + } + else + { + position = getPosition() + getRegion()->getOriginAgent();; + rotation = getRotation(); + } + + // trees have bizzare scaling rules... because it's cool to make needless exceptions + // PS: the trees are the last remaining tidbit of Philip's code. take a look sometime. + F32 radius = getScale().length() * 0.05f; + LLVector3 scale = LLVector3(1,1,1) * radius; + + // compose final matrix + LLMatrix4 local_matrix; + local_matrix.initAll(scale, rotation, position); + + + generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, + nodep->mSilhouetteSegments, + LLVector3(0,0,0), local_matrix, LLMatrix3()); + + nodep->mSilhouetteExists = TRUE; +} diff --git a/linden/indra/newview/llvotree.h b/linden/indra/newview/llvotree.h index 855c612b8..57116cc37 100644 --- a/linden/indra/newview/llvotree.h +++ b/linden/indra/newview/llvotree.h @@ -39,7 +39,7 @@ class LLFace; class LLDrawPool; - +class LLSelectNode; class LLVOTree : public LLViewerObject { @@ -124,6 +124,9 @@ class LLVOTree : public LLViewerObject LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point ); + void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point); + + static S32 sMaxTreeSpecies; struct TreeSpeciesData @@ -200,6 +203,15 @@ class LLVOTree : public LLViewerObject static S32 sLODVertexCount[4]; static S32 sLODSlices[4]; static F32 sLODAngles[4]; + +private: + void generateSilhouetteVertices(std::vector<LLVector3> &vertices, + std::vector<LLVector3> &normals, + std::vector<S32> &segments, + const LLVector3& view_vec, + const LLMatrix4& mat, + const LLMatrix3& norm_mat); + }; #endif diff --git a/linden/indra/newview/llvovolume.cpp b/linden/indra/newview/llvovolume.cpp index f3b8447cf..73ff86073 100644 --- a/linden/indra/newview/llvovolume.cpp +++ b/linden/indra/newview/llvovolume.cpp @@ -1698,7 +1698,7 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p trans_mat.translate(getRegion()->getOriginAgent()); } - volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, trans_mat, mRelativeXformInvTrans); + volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask()); nodep->mSilhouetteExists = TRUE; } diff --git a/linden/indra/newview/llwatchdog.cpp b/linden/indra/newview/llwatchdog.cpp index 330bc8a39..9af050c4c 100644 --- a/linden/indra/newview/llwatchdog.cpp +++ b/linden/indra/newview/llwatchdog.cpp @@ -184,8 +184,8 @@ void LLWatchdog::init(killer_event_callback func) mKillerCallback = func; if(!mSuspectsAccessMutex && !mTimer) { - mSuspectsAccessMutex = new LLMutex(NULL); - mTimer = new LLWatchdogTimerThread(); + mSuspectsAccessMutex = new LLMutex; + mTimer = new LLWatchdogTimerThread; mTimer->setSleepTime(WATCHDOG_SLEEP_TIME_USEC / 1000); mLastClockCount = LLTimer::getTotalTime(); diff --git a/linden/indra/newview/llwatchdog.h b/linden/indra/newview/llwatchdog.h index ed7d5bdcf..1a10e331d 100644 --- a/linden/indra/newview/llwatchdog.h +++ b/linden/indra/newview/llwatchdog.h @@ -64,9 +64,10 @@ class LLWatchdogTimeout : public LLWatchdogEntry /* virtual */ bool isAlive() const; /* virtual */ void reset(); - /* virtual */ void start(const std::string& state); + /* virtual */ void start() { start(""); }; /* virtual */ void stop(); + void start(const std::string& state); void setTimeout(F32 d); void ping(const std::string& state); const std::string& getState() {return mPingState; } diff --git a/linden/indra/newview/llwaterparammanager.cpp b/linden/indra/newview/llwaterparammanager.cpp index e01506e94..015662217 100644 --- a/linden/indra/newview/llwaterparammanager.cpp +++ b/linden/indra/newview/llwaterparammanager.cpp @@ -75,6 +75,7 @@ #include "curl/curl.h" LLWaterParamManager * LLWaterParamManager::sInstance = NULL; +LLFrameTimer waterSmoothTransitionTimer; LLWaterParamManager::LLWaterParamManager() : mFogColor(22.f/255.f, 43.f/255.f, 54.f/255.f, 0.0f, 0.0f, "waterFogColor", "WaterFogColor"), @@ -454,9 +455,44 @@ void LLWaterParamManager::update(LLViewerCamera * cam) shaders_iter->mUniformsDirty = TRUE; } } + //Mix windlight settings if needed + if(sNeedsMix == TRUE) + { + if(sMixSet == NULL) + { + sNeedsMix = FALSE; + return; + } + if (waterSmoothTransitionTimer.getElapsedTimeF32() >= + (sMixTime / 100)) //100 steps inbetween + { + waterSmoothTransitionTimer.reset(); + mCurParams.mix(mCurParams, *sMixSet, sMixCount / 100);//.01 to 1.0 + } + sMixCount++; + if((sMixCount / 100) == 1) + { + //All done + sNeedsMix = FALSE; + std::string wlWaterPresetName = "(Region settings)"; + mCurParams.mName = wlWaterPresetName; + removeParamSet( wlWaterPresetName, true ); + addParamSet( wlWaterPresetName, mCurParams ); + savePreset( wlWaterPresetName ); + loadPreset( wlWaterPresetName, true ); + sMixSet = NULL; + } + } } } - +void LLWaterParamManager::SetMixTime(LLWaterParamSet *mixSet, F32 mixTime) +{ + waterSmoothTransitionTimer.reset(); + sNeedsMix = TRUE; + sMixSet = mixSet; + sMixTime = mixTime; + sMixCount = 1; +} // static void LLWaterParamManager::initClass(void) { diff --git a/linden/indra/newview/llwaterparammanager.h b/linden/indra/newview/llwaterparammanager.h index 588e43689..96dd1aa28 100644 --- a/linden/indra/newview/llwaterparammanager.h +++ b/linden/indra/newview/llwaterparammanager.h @@ -304,6 +304,8 @@ class LLWaterParamManager // singleton pattern implementation static LLWaterParamManager * instance(); + void SetMixTime(LLWaterParamSet* mixSet, F32 mixTime); + public: LLWaterParamSet mCurParams; @@ -334,6 +336,11 @@ class LLWaterParamManager LLVector4 mWaterPlane; F32 mWaterFogKS; + BOOL sNeedsMix; + LLWaterParamSet* sMixSet; + F32 sMixTime; + F32 sMixCount; + // our parameter manager singleton instance static LLWaterParamManager * sInstance; diff --git a/linden/indra/newview/llwaterparamset.cpp b/linden/indra/newview/llwaterparamset.cpp index a26ccedfb..4b2e42608 100644 --- a/linden/indra/newview/llwaterparamset.cpp +++ b/linden/indra/newview/llwaterparamset.cpp @@ -229,4 +229,96 @@ F32 LLWaterParamSet::getFloat(const std::string& paramName, bool& error) error = true; return 0; } +void LLWaterParamSet::mix(LLWaterParamSet& src, LLWaterParamSet& dest, F32 weight) +{ + // set up the iterators + LLSD::map_iterator cIt = mParamValues.beginMap(); + + LLSD srcVal; + LLSD destVal; + + // do the interpolation for all the ones saved as vectors + // skip the weird ones + for(; cIt != mParamValues.endMap(); cIt++) { + + // check params to make sure they're actually there + if(src.mParamValues.has(cIt->first)) + { + srcVal = src.mParamValues[cIt->first]; + } + else + { + continue; + } + + if(dest.mParamValues.has(cIt->first)) + { + destVal = dest.mParamValues[cIt->first]; + } + else + { + continue; + } + + // skip if not a vector + if(!cIt->second.isArray()) + { + continue; + } + + // only Real vectors allowed + if(!cIt->second[0].isReal()) + { + continue; + } + + // make sure all the same size + if( cIt->second.size() != srcVal.size() || + cIt->second.size() != destVal.size()) + { + continue; + } + + // more error checking might be necessary; + + for(int i=0; i < cIt->second.size(); ++i) + { + cIt->second[i] = (1.0f - weight) * (F32) srcVal[i].asReal() + + weight * (F32) destVal[i].asReal(); + } + } + mParamValues["waterFogColor"][0] = (1 - weight) * (F32) src.mParamValues["waterFogColor"][0].asReal() + + weight * (F32) dest.mParamValues["waterFogColor"][0].asReal(); + mParamValues["waterFogColor"][1] = (1 - weight) * (F32) src.mParamValues["waterFogColor"][1].asReal() + + weight * (F32) dest.mParamValues["waterFogColor"][1].asReal(); + mParamValues["waterFogColor"][2] = (1 - weight) * (F32) src.mParamValues["waterFogColor"][2].asReal() + + weight * (F32) dest.mParamValues["waterFogColor"][2].asReal(); + mParamValues["waterFogColor"][3] = (1 - weight) * (F32) src.mParamValues["waterFogColor"][3].asReal() + + weight * (F32) dest.mParamValues["waterFogColor"][3].asReal(); + + mParamValues["waterFogDensity"] = (1 - weight) * (F32) src.mParamValues["waterFogDensity"].asReal() + + weight * (F32) dest.mParamValues["waterFogDensity"].asReal(); + mParamValues["underWaterFogMod"] = (1 - weight) * (F32) src.mParamValues["underWaterFogMod"].asReal() + + weight * (F32) dest.mParamValues["underWaterFogMod"].asReal(); + mParamValues["fresnelScale"] = (1 - weight) * (F32) src.mParamValues["fresnelScale"].asReal() + + weight * (F32) dest.mParamValues["fresnelScale"].asReal(); + mParamValues["fresnelOffset"] = (1 - weight) * (F32) src.mParamValues["fresnelOffset"].asReal() + + weight * (F32) dest.mParamValues["fresnelOffset"].asReal(); + mParamValues["scaleAbove"] = (1 - weight) * (F32) src.mParamValues["scaleAbove"].asReal() + + weight * (F32) dest.mParamValues["scaleAbove"].asReal(); + mParamValues["scaleBelow"] = (1 - weight) * (F32) src.mParamValues["scaleBelow"].asReal() + + weight * (F32) dest.mParamValues["scaleBelow"].asReal(); + mParamValues["blurMultiplier"] = (1 - weight) * (F32) src.mParamValues["blurMultiplier"].asReal() + + weight * (F32) dest.mParamValues["blurMultiplier"].asReal(); + + mParamValues["wave2Dir"][0] = (1 - weight) * (F32) src.mParamValues["wave2Dir"][0].asReal() + + weight * (F32) dest.mParamValues["wave2Dir"][0].asReal(); + mParamValues["wave2Dir"][1] = (1 - weight) * (F32) src.mParamValues["wave2Dir"][1].asReal() + + weight * (F32) dest.mParamValues["wave2Dir"][1].asReal(); + + mParamValues["wave1Dir"][0] = (1 - weight) * (F32) src.mParamValues["wave1Dir"][0].asReal() + + weight * (F32) dest.mParamValues["wave1Dir"][0].asReal(); + mParamValues["wave1Dir"][1] = (1 - weight) * (F32) src.mParamValues["wave1Dir"][1].asReal() + + weight * (F32) dest.mParamValues["wave1Dir"][1].asReal(); +} diff --git a/linden/indra/newview/llweb.cpp b/linden/indra/newview/llweb.cpp index fb4b063eb..7021b4815 100644 --- a/linden/indra/newview/llweb.cpp +++ b/linden/indra/newview/llweb.cpp @@ -38,7 +38,7 @@ #include "llviewerwindow.h" #include "llviewercontrol.h" -#include "llfloaterhtmlhelp.h" +#include "llfloatermediabrowser.h" // static void LLWeb::initClass() diff --git a/linden/indra/newview/llwebbrowserctrl.cpp b/linden/indra/newview/llwebbrowserctrl.cpp deleted file mode 100644 index 453b9d297..000000000 --- a/linden/indra/newview/llwebbrowserctrl.cpp +++ /dev/null @@ -1,1068 +0,0 @@ -/** - * @file llwebbrowserctrl.cpp - * @brief Web browser UI control - * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - - -#include "llwebbrowserctrl.h" - -// viewer includes -#include "llfloaterhtml.h" -#include "llfloaterworldmap.h" -#include "lluictrlfactory.h" -#include "llurldispatcher.h" -#include "llurlsimstring.h" -#include "llviewborder.h" -#include "llviewercontrol.h" -#include "llviewerwindow.h" -#include "llnotifications.h" -#include "llweb.h" -#include "llrender.h" - -// linden library includes -#include "llfocusmgr.h" - -extern BOOL gRestoreGL; - -// Setting the mozilla buffer width to 2048 exactly doesn't work, since it pads its rowbytes a bit, pushing the texture width over 2048. -// 2000 should give enough headroom for any amount of padding it cares to add. -const S32 MAX_DIMENSION = 2000; -const S32 MAX_TEXTURE_DIMENSION = 2048; - -static LLRegisterWidget<LLWebBrowserCtrl> r("web_browser"); - -LLWebBrowserCtrl::LLWebBrowserCtrl( const std::string& name, const LLRect& rect ) : - LLUICtrl( name, rect, FALSE, NULL, NULL ), - mTextureDepthBytes( 4 ), - mWebBrowserImage( 0 ), - mEmbeddedBrowserWindowId( 0 ), - mBorder(NULL), - mFrequentUpdates( true ), - mForceUpdate( false ), - mOpenLinksInExternalBrowser( false ), - mOpenLinksInInternalBrowser( false ), - mTrusted( false ), - mHomePageUrl( "" ), - mIgnoreUIScale( true ), - mAlwaysRefresh( false ), - mExternalUrl( "" ), - mMediaSource( 0 ), - mTakeFocusOnClick( true ), - mCurrentNavUrl( "about:blank" ) -{ - S32 screen_width = mIgnoreUIScale ? - llround((F32)getRect().getWidth() * LLUI::sGLScaleFactor.mV[VX]) : getRect().getWidth(); - S32 screen_height = mIgnoreUIScale ? - llround((F32)getRect().getHeight() * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight(); - - - LLMediaManager *mgr = LLMediaManager::getInstance(); - - if (!mgr) - { - llwarns << "cannot get media manager" << llendl; - return; - } - - mMediaSource = mgr->createSourceFromMimeType("http", "text/html" ); - if ( !mMediaSource ) - { - llwarns << "media source create failed " << llendl; - // return; - } - else - { - - // mMediaSource->init(); - mMediaSource->addCommand( LLMediaBase::COMMAND_START ); - - // observe the browser so we can trap HREF events) - mMediaSource->addObserver(this); - - // create a new texture (based on LLDynamic texture) that will be used to display the output - mWebBrowserImage = new LLWebBrowserTexture( screen_width, screen_height, this, mMediaSource ); - } - - LLRect border_rect( 0, getRect().getHeight() + 2, getRect().getWidth() + 2, 0 ); - mBorder = new LLViewBorder( std::string("web control border"), border_rect, LLViewBorder::BEVEL_IN ); - addChild( mBorder ); -} - -//////////////////////////////////////////////////////////////////////////////// -// note: this is now a singleton and destruction happens via initClass() now -LLWebBrowserCtrl::~LLWebBrowserCtrl() -{ - LLMediaManager *mgr = LLMediaManager::getInstance(); - - if (!mgr) - { - llwarns << "cannot get media manager" << llendl; - return; - } - - if (mMediaSource) - { - mgr->destroySource(mMediaSource); - mMediaSource = NULL; - } - - if ( mWebBrowserImage ) - { - delete mWebBrowserImage; - mWebBrowserImage = 0; - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLWebBrowserCtrl::addObserver( LLWebBrowserCtrlObserver* subjectIn ) -{ - return mEventEmitter.addObserver( subjectIn ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLWebBrowserCtrl::remObserver( LLWebBrowserCtrlObserver* subjectIn ) -{ - return mEventEmitter.remObserver( subjectIn ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::setBorderVisible( BOOL border_visible ) -{ - if ( mBorder ) - { - mBorder->setVisible( border_visible ); - }; -}; - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::setTakeFocusOnClick( bool take_focus ) -{ - mTakeFocusOnClick = take_focus; -} - -//////////////////////////////////////////////////////////////////////////////// -// set flag that forces the embedded browser to open links in the external system browser -void LLWebBrowserCtrl::setOpenInExternalBrowser( bool valIn ) -{ - mOpenLinksInExternalBrowser = valIn; -}; - -//////////////////////////////////////////////////////////////////////////////// -// set flag that forces the embedded browser to open links in the internal browser floater -void LLWebBrowserCtrl::setOpenInInternalBrowser( bool valIn ) -{ - mOpenLinksInInternalBrowser = valIn; -}; - -//////////////////////////////////////////////////////////////////////////////// -void LLWebBrowserCtrl::setTrusted( bool valIn ) -{ - mTrusted = valIn; -} - -//////////////////////////////////////////////////////////////////////////////// -// -BOOL LLWebBrowserCtrl::handleHover( S32 x, S32 y, MASK mask ) -{ - convertInputCoords(x, y); - - if (mMediaSource) - mMediaSource->mouseMove(x, y); - - return TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -// -BOOL LLWebBrowserCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks ) -{ - if (mMediaSource) - mMediaSource->scrollByLines(clicks); - - return TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -// -BOOL LLWebBrowserCtrl::handleMouseUp( S32 x, S32 y, MASK mask ) -{ - convertInputCoords(x, y); - - if (mMediaSource) - { - mMediaSource->mouseUp(x, y); - - // *HACK: LLMediaImplLLMozLib automatically takes focus on mouseup, - // in addition to the onFocusReceived() call below. Undo this. JC - if (!mTakeFocusOnClick) - { - mMediaSource->focus(false); - gViewerWindow->focusClient(); - } - } - - gFocusMgr.setMouseCapture( NULL ); - - return TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -// -BOOL LLWebBrowserCtrl::handleMouseDown( S32 x, S32 y, MASK mask ) -{ - convertInputCoords(x, y); - - if (mMediaSource) - mMediaSource->mouseDown(x, y); - - gFocusMgr.setMouseCapture( this ); - - if (mTakeFocusOnClick) - { - setFocus( TRUE ); - } - - return TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -// -BOOL LLWebBrowserCtrl::handleDoubleClick( S32 x, S32 y, MASK mask ) -{ - convertInputCoords(x, y); - - if (mMediaSource) - mMediaSource->mouseLeftDoubleClick( x, y ); - - gFocusMgr.setMouseCapture( this ); - - if (mTakeFocusOnClick) - { - setFocus( TRUE ); - } - - return TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::onFocusReceived() -{ - if (mMediaSource) - mMediaSource->focus(true); - - - LLUICtrl::onFocusReceived(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::onFocusLost() -{ - if (mMediaSource) - mMediaSource->focus(false); - - gViewerWindow->focusClient(); - - LLUICtrl::onFocusLost(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -BOOL LLWebBrowserCtrl::handleKeyHere( KEY key, MASK mask ) -{ - unsigned long media_key; - - // First, turn SL internal keycode enum into Mozilla keycode enum - - // We don't have to deal with printable characters here - they should - // go through handleUnicodeChar(). This table could be more complete - // than it is, but I think this covers all of the important - // non-printables. - - switch (key) - { - case KEY_BACKSPACE: - media_key = LL_MEDIA_KEY_BACKSPACE; break; - case KEY_TAB: - media_key = LL_MEDIA_KEY_TAB; break; - case KEY_RETURN: - media_key = LL_MEDIA_KEY_RETURN; break; - case KEY_PAD_RETURN: - media_key = LL_MEDIA_KEY_PAD_RETURN; break; - case KEY_ESCAPE: - media_key = LL_MEDIA_KEY_ESCAPE; break; - case KEY_PAGE_UP: - media_key = LL_MEDIA_KEY_PAGE_UP; break; - case KEY_PAGE_DOWN: - media_key = LL_MEDIA_KEY_PAGE_DOWN; break; - case KEY_END: - media_key = LL_MEDIA_KEY_END; break; - case KEY_HOME: - media_key = LL_MEDIA_KEY_HOME; break; - case KEY_LEFT: - media_key = LL_MEDIA_KEY_LEFT; break; - case KEY_UP: - media_key = LL_MEDIA_KEY_UP; break; - case KEY_RIGHT: - media_key = LL_MEDIA_KEY_RIGHT; break; - case KEY_DOWN: - media_key = LL_MEDIA_KEY_DOWN; break; - case KEY_INSERT: - media_key = LL_MEDIA_KEY_INSERT; break; - case KEY_DELETE: - media_key = LL_MEDIA_KEY_DELETE; break; - default: - llinfos << "Don't know how to map LL keycode " << U32(key) - << " to DOM key. Ignoring." << llendl; - return FALSE; // don't know how to map this key. - } - - if (mMediaSource) - mMediaSource->keyPress(media_key); - - return TRUE; -} - -BOOL LLWebBrowserCtrl::handleUnicodeCharHere(llwchar uni_char) -{ - // only accept 'printable' characters, sigh... - if (uni_char >= 32 // discard 'control' characters - && uni_char != 127) // SDL thinks this is 'delete' - yuck. - { - if (mMediaSource) - mMediaSource->unicodeInput(uni_char); - } - - return TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::onVisibilityChange ( BOOL new_visibility ) -{ - // set state of frequent updates automatically if visibility changes - if ( new_visibility ) - { - mFrequentUpdates = true; - } - else - { - mFrequentUpdates = false; - } - LLUICtrl::onVisibilityChange(new_visibility); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::reshape( S32 width, S32 height, BOOL called_from_parent ) -{ - S32 screen_width = mIgnoreUIScale ? llround((F32)width * LLUI::sGLScaleFactor.mV[VX]) : width; - S32 screen_height = mIgnoreUIScale ? llround((F32)height * LLUI::sGLScaleFactor.mV[VY]) : height; - - // when floater is minimized, these sizes are negative - if ( mWebBrowserImage && screen_height > 0 && screen_width > 0 ) - { - mWebBrowserImage->resize( screen_width, screen_height ); - mForceUpdate = true; - } - - LLUICtrl::reshape( width, height, called_from_parent ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::navigateBack() -{ - if (mMediaSource) - mMediaSource->navigateBack(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::navigateForward() -{ - if (mMediaSource) - mMediaSource->navigateForward(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLWebBrowserCtrl::canNavigateBack() -{ - if (mMediaSource) - return mMediaSource->canNavigateBack(); - else - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLWebBrowserCtrl::canNavigateForward() -{ - if (mMediaSource) - return mMediaSource->canNavigateForward(); - else - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLWebBrowserCtrl::set404RedirectUrl( std::string redirect_url ) -{ - if(mMediaSource) - return mMediaSource->set404RedirectUrl( redirect_url ); - else - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLWebBrowserCtrl::clr404RedirectUrl() -{ - if(mMediaSource) - return mMediaSource->clr404RedirectUrl(); - else - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::navigateTo( std::string urlIn ) -{ - // don't browse to anything that starts with secondlife:// or sl:// - const std::string protocol1 = "secondlife://"; - const std::string protocol2 = "sl://"; - if ((LLStringUtil::compareInsensitive(urlIn.substr(0, protocol1.length()), protocol1) == 0) || - (LLStringUtil::compareInsensitive(urlIn.substr(0, protocol2.length()), protocol2) == 0)) - { - // TODO: Print out/log this attempt? - // llinfos << "Rejecting attempt to load restricted website :" << urlIn << llendl; - return; - } - - if (mMediaSource) - { - mCurrentNavUrl = urlIn; - mMediaSource->navigateTo(urlIn); - } -} - - -void LLWebBrowserCtrl::navigateToLocalPage( const std::string& subdir, const std::string& filename_in ) -{ - std::string language = LLUI::getLanguage(); - std::string delim = gDirUtilp->getDirDelimiter(); - std::string filename; - - filename += subdir; - filename += delim; - filename += filename_in; - - std::string expanded_filename = gDirUtilp->findSkinnedFilename("html", language, filename); - - if (gDirUtilp->fileExists(expanded_filename)) - { - navigateTo(expanded_filename); - return; - } - if (language != "en-us") - { - expanded_filename = gDirUtilp->findSkinnedFilename("html", "en-us", filename); - if (gDirUtilp->fileExists(expanded_filename)) - { - navigateTo(expanded_filename); - return; - } - } - - llwarns << "File " << subdir << delim << filename_in << "not found" << llendl; -} - - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::navigateHome() -{ - if( mHomePageUrl.length() ) - { - if (mMediaSource) - mMediaSource->navigateTo(mHomePageUrl); - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::setHomePageUrl( const std::string urlIn ) -{ - mHomePageUrl = urlIn; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLWebBrowserCtrl::setCaretColor(unsigned int red, unsigned int green, unsigned int blue) -{ - if (mMediaSource) - return mMediaSource->setCaretColor(red, green, blue); - else - return false; -} -//////////////////////////////////////////////////////////////////////////////// -// -std::string LLWebBrowserCtrl::getHomePageUrl() -{ - return mHomePageUrl; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserCtrl::draw() -{ - if ( ! mWebBrowserImage ) - return; - - if ( gRestoreGL == 1 ) - { - LLRect r = getRect(); - mMediaSource->updateMedia(); - reshape( r.getWidth(), r.getHeight(), FALSE ); - return; - }; - - // NOTE: optimization needed here - probably only need to do this once - // unless tearoffs change the parent which they probably do. - const LLUICtrl* ptr = findRootMostFocusRoot(); - if ( ptr && ptr->hasFocus() ) - { - setFrequentUpdates( true ); - } - else - { - setFrequentUpdates( false ); - }; - - // alpha off for this - LLGLSUIDefault gls_ui; - LLGLDisable gls_alphaTest( GL_ALPHA_TEST ); - - gGL.pushMatrix(); - { - if (mIgnoreUIScale) - { - glLoadIdentity(); - // font system stores true screen origin, need to scale this by UI scale factor - // to get render origin for this view (with unit scale) - gGL.translatef(floorf(LLFontGL::sCurOrigin.mX * LLUI::sGLScaleFactor.mV[VX]), - floorf(LLFontGL::sCurOrigin.mY * LLUI::sGLScaleFactor.mV[VY]), - LLFontGL::sCurOrigin.mZ); - } - - // scale texture to fit the space using texture coords - gGL.getTexUnit(0)->bind(mWebBrowserImage->getTexture()); - gGL.color4fv( LLColor4::white.mV ); - F32 max_u = ( F32 )mWebBrowserImage->getBrowserWidth() / ( F32 )mWebBrowserImage->getWidth(); - F32 max_v = ( F32 )mWebBrowserImage->getBrowserHeight() / ( F32 )mWebBrowserImage->getHeight(); - - // draw the browser - gGL.setSceneBlendType(LLRender::BT_REPLACE); - gGL.begin( LLRender::QUADS ); - { - // render using web browser reported width and height, instead of trying to invert GL scale - gGL.texCoord2f( max_u, max_v ); - gGL.vertex2i( mWebBrowserImage->getBrowserWidth(), mWebBrowserImage->getBrowserHeight() ); - - gGL.texCoord2f( 0.f, max_v ); - gGL.vertex2i( 0, mWebBrowserImage->getBrowserHeight() ); - - gGL.texCoord2f( 0.f, 0.f ); - gGL.vertex2i( 0, 0 ); - - gGL.texCoord2f( max_u, 0.f ); - gGL.vertex2i( mWebBrowserImage->getBrowserWidth(), 0 ); - } - gGL.end(); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - gGL.popMatrix(); - - // highlight if keyboard focus here. (TODO: this needs some work) - if ( mBorder->getVisible() ) - mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) ); - - - LLUICtrl::draw(); -} - -void LLWebBrowserCtrl::convertInputCoords(S32& x, S32& y) -{ - x = mIgnoreUIScale ? llround((F32)x * LLUI::sGLScaleFactor.mV[VX]) : x; - y = mIgnoreUIScale ? llround((F32)(getRect().getHeight() - y) * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight() - y; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLWebBrowserCtrl::onNavigateBegin( const EventType& eventIn ) -{ - LLWebBrowserCtrlEvent event( eventIn.getStringValue() ); - mEventEmitter.update( &LLWebBrowserCtrlObserver::onNavigateBegin, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLWebBrowserCtrl::onNavigateComplete( const EventType& eventIn ) -{ - // chain this event on to observers of an instance of LLWebBrowserCtrl - LLWebBrowserCtrlEvent event( eventIn.getStringValue() ); - mEventEmitter.update( &LLWebBrowserCtrlObserver::onNavigateComplete, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLWebBrowserCtrl::onUpdateProgress( const EventType& eventIn ) -{ - // chain this event on to observers of an instance of LLWebBrowserCtrl - LLWebBrowserCtrlEvent event( eventIn.getIntValue() ); - mEventEmitter.update( &LLWebBrowserCtrlObserver::onUpdateProgress, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLWebBrowserCtrl::onStatusTextChange( const EventType& eventIn ) -{ - // chain this event on to observers of an instance of LLWebBrowserCtrl - LLWebBrowserCtrlEvent event( eventIn.getStringValue() ); - mEventEmitter.update( &LLWebBrowserCtrlObserver::onStatusTextChange, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLWebBrowserCtrl::onLocationChange( const EventType& eventIn ) -{ - // chain this event on to observers of an instance of LLWebBrowserCtrl - LLWebBrowserCtrlEvent event( eventIn.getStringValue() ); - mEventEmitter.update( &LLWebBrowserCtrlObserver::onLocationChange, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLWebBrowserCtrl::onMediaContentsChange( const EventType& event_in ) -{ - if ( mWebBrowserImage ) - { - mWebBrowserImage->setNeedsUpdate(); - mForceUpdate = true; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// static -bool LLWebBrowserCtrl::onClickLinkExternalTarget(const LLSD& notification, const LLSD& response ) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if ( 0 == option ) - { - // open in external browser because we don't support - // creation of our own secondary browser windows - LLWeb::loadURLExternal( notification["payload"]["external_url"].asString() ); - } - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLWebBrowserCtrl::onClickLinkHref( const EventType& eventIn ) -{ - // if there is a value for the target (passed in stringValueEx) - if ( eventIn.getStringValueEx().length() ) - { - // if the target = "_new" - if ( eventIn.getStringValueEx() == "_external" ) - { - mExternalUrl = eventIn.getStringValue(); - LLSD payload; - payload["external_url"] = mExternalUrl; - LLNotifications::instance().add( "WebLaunchExternalTarget", LLSD(), payload, onClickLinkExternalTarget); - return; - } - } - - const std::string protocol1( "http://" ); - const std::string protocol2( "https://" ); - if( mOpenLinksInExternalBrowser ) - { - if ( eventIn.getStringValue().length() ) - { - if ( LLStringUtil::compareInsensitive( eventIn.getStringValue().substr( 0, protocol1.length() ), protocol1 ) == 0 || - LLStringUtil::compareInsensitive( eventIn.getStringValue().substr( 0, protocol2.length() ), protocol2 ) == 0 ) - { - LLWeb::loadURLExternal( eventIn.getStringValue() ); - } - } - } - else - if( mOpenLinksInInternalBrowser ) - { - if ( eventIn.getStringValue().length() ) - { - if ( LLStringUtil::compareInsensitive( eventIn.getStringValue().substr( 0, protocol1.length() ), protocol1 ) == 0 || - LLStringUtil::compareInsensitive( eventIn.getStringValue().substr( 0, protocol2.length() ), protocol2 ) == 0 ) - { - // If we spawn a new LLFloaterHTML, assume we want it to - // follow this LLWebBrowserCtrl's trust for whether or - // not to open secondlife:///app/ links. JC. - const bool open_links_externally = false; - LLFloaterHtml::getInstance()->show( - eventIn.getStringValue(), - "Second Life Browser", - open_links_externally, - mTrusted); - } - } - } - - // chain this event on to observers of an instance of LLWebBrowserCtrl - LLWebBrowserCtrlEvent event( eventIn.getStringValue(), eventIn.getStringValueEx() ); - mEventEmitter.update( &LLWebBrowserCtrlObserver::onClickLinkHref, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLWebBrowserCtrl::onClickLinkNoFollow( const EventType& eventIn ) -{ - std::string url = eventIn.getStringValue(); - if (LLURLDispatcher::isSLURLCommand(url) - && !mTrusted) - { - // block handling of this secondlife:///app/ URL - LLNotifications::instance().add("UnableToOpenCommandURL"); - return; - } - - LLURLDispatcher::dispatch(url, this, mTrusted); - - // chain this event on to observers of an instance of LLWebBrowserCtrl - LLWebBrowserCtrlEvent event( eventIn.getStringValue() ); - mEventEmitter.update( &LLWebBrowserCtrlObserver::onClickLinkNoFollow, event ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -LLWebBrowserTexture::LLWebBrowserTexture( S32 width, S32 height, LLWebBrowserCtrl* browserCtrl, LLMediaBase *media_source ) : - LLDynamicTexture( 512, 512, 4, ORDER_FIRST, TRUE ), - mLastBrowserDepth( 0 ), - mNeedsUpdate( true ), - mWebBrowserCtrl( browserCtrl ), - mMediaSource(media_source) -{ - mElapsedTime.start(); - - resize( width, height ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -LLWebBrowserTexture::~LLWebBrowserTexture() -{ - mElapsedTime.stop(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -BOOL LLWebBrowserTexture::needsRender() -{ - if ( mWebBrowserCtrl->getFrequentUpdates() || - mWebBrowserCtrl->getAlwaysRefresh() || - mWebBrowserCtrl->getForceUpdate() ) - { - // only update mozilla/texture occasionally - if ( mElapsedTime.getElapsedTimeF32() > ( 1.0f / 15.0f ) ) - { - return TRUE; - } - } - - return FALSE; -} - -//////////////////////////////////////////////////////////////////////////////// -// -BOOL LLWebBrowserTexture::render() -{ - if (!mMediaSource) - return FALSE; - - // frequent updates turned on? - if ( mWebBrowserCtrl->getFrequentUpdates() || - mWebBrowserCtrl->getAlwaysRefresh() || - mWebBrowserCtrl->getForceUpdate() ) - { - - if ( mNeedsUpdate ) - { - - const unsigned char* pixels = mMediaSource->getMediaData(); - if ( ! pixels ) - return FALSE; - - mNeedsUpdate = false; - mWebBrowserCtrl->setForceUpdate(false); - - S32 media_depth = mMediaSource->getMediaDepth(); - S32 media_width = mMediaSource->getMediaWidth(); - S32 media_height = mMediaSource->getMediaHeight(); - - // these are both invalid conditions and should never happen but SL-27583 indicates it does - if ((media_width < 1) || (media_depth < 2)) - return FALSE; - - // Browser depth hasn't changed. - if(mLastBrowserDepth == media_depth) - { - S32 width = llmin(media_width, mBrowserWidth); - S32 height = llmin(media_height, mBrowserHeight); - - S32 media_data_width = mMediaSource->getMediaDataWidth(); - S32 media_data_height = mMediaSource->getMediaDataHeight(); - - // Just grab the pixels. - if ( media_data_width > 0 && media_data_height > 0 && - media_data_width < MAX_DIMENSION && media_data_height < MAX_DIMENSION ) - { - mTexture->setSubImage( pixels, - media_data_width, media_data_height, - 0, 0, - llmin(width, media_data_width), llmin(media_data_height, height) ); - }; - } - else - { - // Browser depth has changed -- need to recreate texture to match. - resize(mBrowserWidth, mBrowserHeight); - }; - }; - }; - - return TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -// -S32 LLWebBrowserTexture::getBrowserWidth() -{ - return mBrowserWidth; -} - -//////////////////////////////////////////////////////////////////////////////// -// -S32 LLWebBrowserTexture::getBrowserHeight() -{ - return mBrowserHeight; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserTexture::setNeedsUpdate() -{ - mNeedsUpdate = true; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLWebBrowserTexture::resize( S32 new_width, S32 new_height ) -{ - if (!mMediaSource) - return; - - F32 scale_ratio = 1.f; - if (new_width > MAX_DIMENSION) - { - scale_ratio = (F32)MAX_DIMENSION / (F32)new_width; - } - if (new_height > MAX_DIMENSION) - { - scale_ratio = llmin(scale_ratio, (F32)MAX_DIMENSION / (F32)new_height); - } - - mBrowserWidth = llround(scale_ratio * (F32)new_width); - mBrowserHeight = llround(scale_ratio * (F32)new_height); - - mMediaSource->setRequestedMediaSize(mBrowserWidth, mBrowserHeight); - - // HACK - this code is executing a render - resize should call render() instead - // (and render() should be refactored so it doesn't call resize()) - - mMediaSource->updateMedia(); - const unsigned char* pixels = mMediaSource->getMediaData(); - - S32 media_width = mMediaSource->getMediaWidth(); - S32 media_height = mMediaSource->getMediaHeight(); - S32 media_depth = mMediaSource->getMediaDepth(); - - // these are both invalid conditions and should never happen but SL-27583 indicates it does - if ( media_width < 1 || media_depth < 2 ) - return; - - releaseGLTexture(); - - // calculate the next power of 2 bigger than reqquested size for width and height - for ( mWidth = 1; mWidth < mBrowserWidth; mWidth <<= 1 ) - { - if ( mWidth >= MAX_TEXTURE_DIMENSION ) - { - break; - }; - }; - - for ( mHeight = 1; mHeight < mBrowserHeight; mHeight <<= 1 ) - { - if ( mHeight >= MAX_TEXTURE_DIMENSION ) - { - break; - }; - }; - - LLGLint internal_format; - LLGLenum primary_format; - LLGLenum type_format; - BOOL swap_bytes = FALSE; - - switch(media_depth) - { - default: - case 4: - internal_format = GL_RGBA8; - primary_format = GL_BGRA_EXT; - #if LL_DARWIN - #if LL_BIG_ENDIAN - type_format = GL_UNSIGNED_INT_8_8_8_8_REV; - #else - type_format = GL_UNSIGNED_INT_8_8_8_8; - #endif - #else // windows or linux - type_format = GL_UNSIGNED_BYTE; - #endif - break; - - case 2: - #if LL_DARWIN - internal_format = GL_RGBA8; - primary_format = GL_BGRA_EXT; - type_format = GL_UNSIGNED_SHORT_1_5_5_5_REV; - #if LL_LITTLE_ENDIAN - swap_bytes = TRUE; - #endif - #else // windows or linux - // MBW -- XXX -- This is just a guess on my part. Someone needs to verify which GL texture format matches the 16-bit format used on windows. - internal_format = GL_RGB8; - primary_format = GL_RGB; - type_format = GL_UNSIGNED_SHORT_5_6_5; - #endif - break; - } - - // will create mWidth * mHeight sized texture, using BGR ordering - LLDynamicTexture::generateGLTexture(internal_format, primary_format, type_format, swap_bytes); - - - S32 width = llmin(media_width, mBrowserWidth); - S32 height = llmin(media_height, mBrowserHeight); - - S32 media_data_width = mMediaSource->getMediaDataWidth(); - S32 media_data_height = mMediaSource->getMediaDataHeight(); - - if (pixels) - { - mTexture->setSubImage( pixels, media_data_width, media_data_height, - 0, 0, width, height ); - } - - mLastBrowserDepth = media_depth; -} - -// virtual -LLXMLNodePtr LLWebBrowserCtrl::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLUICtrl::getXML(); - - node->setName(LL_WEB_BROWSER_CTRL_TAG); - - return node; -} - -LLView* LLWebBrowserCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("web_browser"); - node->getAttributeString("name", name); - - std::string start_url("start_url"); - node->getAttributeString("start_url", start_url ); - - BOOL border_visible = true; - node->getAttributeBOOL("border_visible", border_visible); - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - LLWebBrowserCtrl* web_browser = new LLWebBrowserCtrl( name, rect ); - - if(node->hasAttribute("caret_color")) - { - LLColor4 color; - LLUICtrlFactory::getAttributeColor(node, "caret_color", color); - LLColor4U colorU = LLColor4U(color); - web_browser->setCaretColor( colorU.mV[0], colorU.mV[1], colorU.mV[2] ); - } - - BOOL ignore_ui_scale = web_browser->getIgnoreUIScale(); - node->getAttributeBOOL("ignore_ui_scale", ignore_ui_scale); - web_browser->setIgnoreUIScale((bool)ignore_ui_scale); - - web_browser->initFromXML(node, parent); - - web_browser->setHomePageUrl( start_url ); - - web_browser->setBorderVisible( border_visible ); - - web_browser->navigateHome(); - - return web_browser; -} - -std::string LLWebBrowserCtrl::getCurrentNavUrl() -{ - return mCurrentNavUrl; -} - diff --git a/linden/indra/newview/llwlparammanager.cpp b/linden/indra/newview/llwlparammanager.cpp index 31471d77c..8007cceed 100644 --- a/linden/indra/newview/llwlparammanager.cpp +++ b/linden/indra/newview/llwlparammanager.cpp @@ -71,11 +71,13 @@ #include "llviewerinventory.h" #include "llviewerregion.h" #include "llassetuploadresponders.h" +#include "llframetimer.h" #include "curl/curl.h" LLWLParamManager * LLWLParamManager::sInstance = NULL; std::vector<LLWLPresetsObserver*> LLWLParamManager::sObservers; +LLFrameTimer wlSmoothTransitionTimer; LLWLParamManager::LLWLParamManager() : @@ -562,6 +564,46 @@ void LLWLParamManager::update(LLViewerCamera * cam) } } } + + //Mix windlight settings if needed + if(sNeedsMix == TRUE) + { + if(sMixSet == NULL) + { + sNeedsMix = FALSE; + return; + } + if (wlSmoothTransitionTimer.getElapsedTimeF32() >= + (sMixTime / 100)) //100 steps inbetween + { + wlSmoothTransitionTimer.reset(); + mCurParams.mix(mCurParams, *sMixSet, sMixCount / 100);//.01 to 1.0 + } + sMixCount++; + if((sMixCount / 100) == 1) + { + //All done + sNeedsMix = FALSE; + std::string wlSkyPresetName = "(Region settings)"; + mCurParams.mName = wlSkyPresetName; + removeParamSet( wlSkyPresetName, true ); + addParamSet( wlSkyPresetName, mCurParams ); + savePreset( wlSkyPresetName ); + mAnimator.mIsRunning = false; + mAnimator.mUseLindenTime = false; + loadPreset( wlSkyPresetName, true ); + sMixSet = NULL; + } + } +} + +void LLWLParamManager::SetMixTime(LLWLParamSet *mixSet, F32 mixTime) +{ + wlSmoothTransitionTimer.reset(); + sNeedsMix = TRUE; + sMixSet = mixSet; + sMixTime = mixTime; + sMixCount = 1; } // static diff --git a/linden/indra/newview/llwlparammanager.h b/linden/indra/newview/llwlparammanager.h index 612a5079f..fc1127e02 100644 --- a/linden/indra/newview/llwlparammanager.h +++ b/linden/indra/newview/llwlparammanager.h @@ -221,6 +221,8 @@ class LLWLParamManager static void removeObserver(LLWLPresetsObserver* observer); static void notifyObservers(); + void SetMixTime(LLWLParamSet* mixSet, F32 mixTime); + public: // helper variables @@ -280,6 +282,11 @@ class LLWLParamManager private: // our parameter manager singleton instance static LLWLParamManager * sInstance; + + BOOL sNeedsMix; + LLWLParamSet* sMixSet; + F32 sMixTime; + F32 sMixCount; static std::vector<LLWLPresetsObserver*> sObservers; diff --git a/linden/indra/newview/llwlparamset.cpp b/linden/indra/newview/llwlparamset.cpp index ea9c00ae8..19528eb25 100644 --- a/linden/indra/newview/llwlparamset.cpp +++ b/linden/indra/newview/llwlparamset.cpp @@ -145,6 +145,11 @@ void LLWLParamSet::set(const std::string& paramName, float x) { mParamValues[paramName][0] = x; } + else + { + //Default this + mParamValues[paramName] = x; + } } void LLWLParamSet::set(const std::string& paramName, float x, float y) { diff --git a/linden/indra/newview/llworld.cpp b/linden/indra/newview/llworld.cpp index ca8ce2d9e..7866bf8f7 100644 --- a/linden/indra/newview/llworld.cpp +++ b/linden/indra/newview/llworld.cpp @@ -60,7 +60,7 @@ #include "pipeline.h" #include "llappviewer.h" // for do_disconnect() -#include "hippoLimits.h" +#include "hippolimits.h" #include <deque> #include <queue> @@ -669,7 +669,8 @@ void LLWorld::updateClouds(const F32 dt) { static BOOL* sFreezeTime = rebind_llcontrol<BOOL>("FreezeTime", &gSavedSettings, true); if ((*sFreezeTime) || - !gSavedSettings.getBOOL("SkyUseClassicClouds")) + !gSavedSettings.getBOOL("SkyUseClassicClouds") || + !gHippoLimits->skyUseClassicClouds) { // don't move clouds in snapshot mode return; @@ -830,6 +831,14 @@ void LLWorld::setLandFarClip(const F32 far_clip) } } +void LLWorld::rebuildClouds(LLViewerRegion *regionp) +{ + regionp->mCloudLayer.destroy(); + regionp->mCloudLayer.create(regionp); + regionp->mCloudLayer.setWidth((F32)mWidth); + regionp->mCloudLayer.setWindPointer(®ionp->mWind); +} + // Some region that we're connected to, but not the one we're in, gave us // a (possibly) new water height. Update it in our local copy. void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_height) diff --git a/linden/indra/newview/llworld.h b/linden/indra/newview/llworld.h index 2c5815cde..964729d49 100644 --- a/linden/indra/newview/llworld.h +++ b/linden/indra/newview/llworld.h @@ -150,6 +150,8 @@ class LLWorld : public LLSingleton<LLWorld> void getInfo(LLSD& info); + void rebuildClouds(LLViewerRegion *regionp); + public: typedef std::list<LLViewerRegion*> region_list_t; const region_list_t& getRegionList() const { return mActiveRegionList; } diff --git a/linden/indra/newview/llworldmap.cpp b/linden/indra/newview/llworldmap.cpp index c6242f6af..3ada36f26 100644 --- a/linden/indra/newview/llworldmap.cpp +++ b/linden/indra/newview/llworldmap.cpp @@ -47,7 +47,7 @@ #include "llviewerimagelist.h" #include "llviewerregion.h" #include "llregionflags.h" - #include "hippoGridManager.h" + #include "hippogridmanager.h" bool LLWorldMap::sGotMapURL = false; const F32 REQUEST_ITEMS_TIMER = 10.f * 60.f; // 10 minutes @@ -735,6 +735,13 @@ void LLWorldMap::processMapBlockReply(LLMessageSystem* msg, void**) callback(handle, LLWorldMap::getInstance()->mSLURL, image_id, LLWorldMap::getInstance()->mSLURLTeleport); } } + if(gAgent.mLureShow) + { + if((x_regions == gAgent.mLureGlobalX) && (y_regions == gAgent.mLureGlobalY)) + { + gAgent.onFoundLureDestination(); + } + } } if(adjust) gFloaterWorldMap->adjustZoomSliderBounds(); diff --git a/linden/indra/newview/llxmlrpctransaction.cpp b/linden/indra/newview/llxmlrpctransaction.cpp index b993c9954..058946eb2 100644 --- a/linden/indra/newview/llxmlrpctransaction.cpp +++ b/linden/indra/newview/llxmlrpctransaction.cpp @@ -35,7 +35,7 @@ #include "llxmlrpctransaction.h" #include "llcurl.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include "llviewercontrol.h" // Have to include these last to avoid queue redefinition! diff --git a/linden/indra/newview/mozilla-powerpc-darwin-readme.txt b/linden/indra/newview/mozilla-powerpc-darwin-readme.txt index be67ad31c..e69de29bb 100644 --- a/linden/indra/newview/mozilla-powerpc-darwin-readme.txt +++ b/linden/indra/newview/mozilla-powerpc-darwin-readme.txt @@ -1,71 +0,0 @@ -NOTE: these directions have been obsoleted. There are now shell scripts that will check out, build, and package the necessary pieces -of the mozilla code in lindelib/mozilla-1.8.0/mac-build. I'm leaving this file here for historical interest. -------------- -Written by Monroe on June 17, 2005. - -Here's how to rebuild the Mozilla components for the Mac build. - -Check out the mozilla source from cvs - -cd to the mozilla directory (the same one that contains client.mk) - -cp .mozconfig.opt.shared.small .mozconfig - -Add the following line to the .mozconfig file you just created: - -ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.2.8.sdk - -make -f client.mk build - -wait a while. - -The build products you need to extract are in objdir-opt-shared-small/dist/bin and objdir-opt-shared-small/dist/lib. - -Copy the following to linden/libraries/firefox-1.0.4/<arch>/lib_release and linden/libraries/firefox-1.0.4/<arch>/lib_release: - -objdir-opt-shared-small/dist/lib/libembed_base_s.a -objdir-opt-shared-small/dist/lib/libxpcomglue_s.a -objdir-opt-shared-small/dist/bin/libxpcom.dylib -objdir-opt-shared-small/dist/bin/libplds4.dylib -objdir-opt-shared-small/dist/bin/libplc4.dylib -objdir-opt-shared-small/dist/bin/libnspr4.dylib -objdir-opt-shared-small/dist/bin/libgkgfx.dylib - -This first part should be repeated with .mozconfig.debug.shared.small to generate the libraries in the two matching lib_debug directories. The debug version of the bin directory is prohibitively large, so we're just using the release version of that part. - -Much of the contents of objdir-opt-shared-small/dist/bin also needs to go into a tar file that will be used when generating the application bundle. - -The bin directory will be populated with symlinks. If you just tar it up as-is, you'll get a tar file full of symlinks, which is not useful. - -Use 'cp -RL source dest' to make a copy of the bin directory with all symlinks expanded. This will be more useful. - -Remove things that aren't needed. This includes at least: - -asdecode -firefox -firefox-bin -firefox-config -LICENSE -nsinstall -mangle -regxpcom -regchrome -README.txt -run-mozilla.sh -xpcshell -xpt_dump -shlibsign -xpt_link -xpidl -xpicleanup - -There may be other pieces that aren't needed as well. I expect this will be refined moving forward. - -Because of the way the tar file will be expanded (directly inside the application bundle, in Contents/MacOS), it's important to create it so that it won't expand at a subdirectory of the current path. The way to to this is to cd to the dist/bin directory and do something like this: - -tar -zcvf ../mozilla-powerpc-darwin.tgz . - -This will create a tar file containing everything in the current directory, and will place the file one level up (so it doesn't interfere with its own creation). This file should replace the file with the above name checked into cvs in linden/indra/newview/. One of the lines in the shell script phase of the build extracts it appropriately into the application bundle. - -If any of this is unclear, please contact Monroe and I'll try to clarify and update this file. - diff --git a/linden/indra/newview/pipeline.cpp b/linden/indra/newview/pipeline.cpp index cf766e0f1..9da0da0f6 100644 --- a/linden/indra/newview/pipeline.cpp +++ b/linden/indra/newview/pipeline.cpp @@ -35,7 +35,7 @@ #include "pipeline.h" // library includes -#include "audioengine.h" // For MAX_BUFFERS for debugging. +#include "llaudioengine.h" // For MAX_BUFFERS for debugging. #include "imageids.h" #include "llerror.h" #include "llviewercontrol.h" @@ -101,6 +101,7 @@ #include "llwaterparammanager.h" #include "llspatialpartition.h" #include "llmutelist.h" +#include "hippolimits.h" // [RLVa:KB] #include "rlvhandler.h" @@ -5772,7 +5773,7 @@ void LLPipeline::renderDeferredLighting() (1 << LLPipeline::RENDER_TYPE_FULLBRIGHT) | (1 << LLPipeline::RENDER_TYPE_VOLUME) | (1 << LLPipeline::RENDER_TYPE_GLOW) | - (1 << LLPipeline::RENDER_TYPE_BUMP)); + (1 << LLPipeline::RENDER_TYPE_BUMP)); renderGeomPostDeferred(*LLViewerCamera::getInstance()); mRenderTypeMask = render_mask; @@ -5980,6 +5981,9 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) stop_glerror(); LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE; + + if (!gSavedSettings.getBOOL("RenderWater") || !gHippoLimits->mRenderWater) + LLPipeline::sUnderWaterRender = FALSE; if (LLPipeline::sUnderWaterRender) { diff --git a/linden/indra/newview/pipeline.h b/linden/indra/newview/pipeline.h index 3f3309a27..1ecb56e92 100644 --- a/linden/indra/newview/pipeline.h +++ b/linden/indra/newview/pipeline.h @@ -316,7 +316,7 @@ class LLPipeline RENDER_TYPE_INVISIBLE = LLDrawPool::POOL_INVISIBLE, RENDER_TYPE_VOIDWATER = LLDrawPool::POOL_VOIDWATER, RENDER_TYPE_WATER = LLDrawPool::POOL_WATER, - RENDER_TYPE_ALPHA = LLDrawPool::POOL_ALPHA, + RENDER_TYPE_ALPHA = LLDrawPool::POOL_ALPHA, RENDER_TYPE_GLOW = LLDrawPool::POOL_GLOW, // Following are object types (only used in drawable mRenderType) diff --git a/linden/indra/newview/primbackup.cpp b/linden/indra/newview/primbackup.cpp index 63043f068..7f050a01c 100644 --- a/linden/indra/newview/primbackup.cpp +++ b/linden/indra/newview/primbackup.cpp @@ -54,7 +54,7 @@ #include "llappviewer.h" #include "lltransactiontypes.h" -#include "hippoGridManager.h" +#include "hippogridmanager.h" #include "primbackup.h" diff --git a/linden/indra/newview/qtoolalign.cpp b/linden/indra/newview/qtoolalign.cpp new file mode 100644 index 000000000..3fe31f7e3 --- /dev/null +++ b/linden/indra/newview/qtoolalign.cpp @@ -0,0 +1,602 @@ +/** + * @file qtoolalign.cpp + * @brief A tool to align objects + * @author Karl Stiefvater (Qarl) + * + * Karl has given permission to use this code under the terms of + * the GNU GPL v2 plus FLOSS exception and/or the GNU LGPL v2.1. + * + * Backported for Viewer 1.X code base by Jacek Antonelli. + */ + +#include "llviewerprecompiledheaders.h" + +// File includes +#include "qtoolalign.h" + +// Library includes +#include "llbbox.h" +#include "v3math.h" + +// Viewer includes +#include "llagent.h" +#include "llbox.h" +#include "llcylinder.h" +#include "llfloatertools.h" +#include "llselectmgr.h" +#include "llviewercamera.h" +#include "llviewercontrol.h" +#include "llviewerobject.h" +#include "llviewerwindow.h" + + +const F32 MANIPULATOR_SIZE = 5.0; +const F32 MANIPULATOR_SELECT_SIZE = 20.0; + + + +QToolAlign::QToolAlign() +: LLTool(std::string("Align")) +{ +} + + +QToolAlign::~QToolAlign() +{ +} + + + +BOOL QToolAlign::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (mHighlightedAxis != -1) + { + align(); + } + else + { + gViewerWindow->pickAsync(x, y, mask, pickCallback); + } + + return TRUE; +} + + + +void QToolAlign::pickCallback(const LLPickInfo& pick_info) +{ + LLViewerObject* object = pick_info.getObject(); + + if (object) + { + if (object->isAvatar()) + { + return; + } + + if (pick_info.mKeyMask & MASK_SHIFT) + { + // If object not selected, select it + if ( !object->isSelected() ) + { + LLSelectMgr::getInstance()->selectObjectAndFamily(object); + } + else + { + LLSelectMgr::getInstance()->deselectObjectAndFamily(object); + } + } + else + { + LLSelectMgr::getInstance()->deselectAll(); + LLSelectMgr::getInstance()->selectObjectAndFamily(object); + } + + } + else + { + if (!(pick_info.mKeyMask == MASK_SHIFT)) + { + LLSelectMgr::getInstance()->deselectAll(); + } + } + + LLSelectMgr::getInstance()->promoteSelectionToRoot(); +} + + + +void QToolAlign::handleSelect() +{ + // no parts, please + + //llwarns << "in select" << llendl; + LLSelectMgr::getInstance()->promoteSelectionToRoot(); + gFloaterTools->setStatusText("align"); +} + + +void QToolAlign::handleDeselect() +{ +} + + +BOOL QToolAlign::findSelectedManipulator(S32 x, S32 y) +{ + mHighlightedAxis = -1; + mHighlightedDirection = 0; + + LLMatrix4 transform; + if (LLSelectMgr::getInstance()->getSelection()->getSelectType() == SELECT_TYPE_HUD) + { + LLVector4 translation(mBBox.getCenterAgent()); + transform.initRotTrans(mBBox.getRotation(), translation); + LLMatrix4 cfr(OGL_TO_CFR_ROTATION); + transform *= cfr; + LLMatrix4 window_scale; + F32 zoom_level = 2.f * gAgent.mHUDCurZoom; + window_scale.initAll(LLVector3(zoom_level / LLViewerCamera::getInstance()->getAspect(), zoom_level, 0.f), + LLQuaternion::DEFAULT, + LLVector3::zero); + transform *= window_scale; + } + else + { + transform.initAll(LLVector3(1.f, 1.f, 1.f), mBBox.getRotation(), mBBox.getCenterAgent()); + + LLMatrix4 projection_matrix = LLViewerCamera::getInstance()->getProjection(); + LLMatrix4 model_matrix = LLViewerCamera::getInstance()->getModelview(); + + transform *= model_matrix; + transform *= projection_matrix; + } + + + //LLRect world_view_rect = getWorldViewRectScaled(); + F32 half_width = (F32)gViewerWindow->getWindowWidth() / 2.f; + F32 half_height = (F32)gViewerWindow->getWindowHeight() / 2.f; + LLVector2 manip2d; + LLVector2 mousePos((F32)x - half_width, (F32)y - half_height); + LLVector2 delta; + + LLVector3 bbox_scale = mBBox.getMaxLocal() - mBBox.getMinLocal(); + + for (S32 axis = VX; axis <= VZ; axis++) + { + for (F32 direction = -1.0; direction <= 1.0; direction += 2.0) + { + LLVector3 axis_vector = LLVector3(0,0,0); + axis_vector.mV[axis] = direction * bbox_scale.mV[axis] / 2.0; + + LLVector4 manipulator_center = LLVector4(axis_vector); + + LLVector4 screen_center = manipulator_center * transform; + screen_center /= screen_center.mV[VW]; + + manip2d.setVec(screen_center.mV[VX] * half_width, screen_center.mV[VY] * half_height); + + delta = manip2d - mousePos; + + if (delta.magVecSquared() < MANIPULATOR_SELECT_SIZE * MANIPULATOR_SELECT_SIZE) + { + mHighlightedAxis = axis; + mHighlightedDirection = direction; + return TRUE; + } + + } + } + + return FALSE; +} + + +BOOL QToolAlign::handleHover(S32 x, S32 y, MASK mask) +{ + if (mask & MASK_SHIFT) + { + mForce = FALSE; + } + else + { + mForce = TRUE; + } + + gViewerWindow->setCursor(UI_CURSOR_ARROW); + return findSelectedManipulator(x, y); +} + + + +void setup_transforms_bbox(LLBBox bbox) +{ + // translate to center + LLVector3 center = bbox.getCenterAgent(); + gGL.translatef(center.mV[VX], center.mV[VY], center.mV[VZ]); + + // rotate + LLQuaternion rotation = bbox.getRotation(); + F32 angle_radians, x, y, z; + rotation.getAngleAxis(&angle_radians, &x, &y, &z); + // gGL has no rotate method (despite having translate and scale) presumably because + // its authors smoke crack. so we hack. + gGL.flush(); + glRotatef(angle_radians * RAD_TO_DEG, x, y, z); + + // scale + LLVector3 scale = bbox.getMaxLocal() - bbox.getMinLocal(); + gGL.scalef(scale.mV[VX], scale.mV[VY], scale.mV[VZ]); +} + + +void render_bbox(LLBBox bbox) +{ + glMatrixMode(GL_MODELVIEW); + gGL.pushMatrix(); + + setup_transforms_bbox(bbox); + + gGL.flush(); + gBox.render(); + + gGL.popMatrix(); +} + +void render_cone_bbox(LLBBox bbox) +{ + glMatrixMode(GL_MODELVIEW); + gGL.pushMatrix(); + + setup_transforms_bbox(bbox); + + gGL.flush(); + gCone.render(CONE_LOD_HIGHEST); + + gGL.popMatrix(); +} + + + +// the selection bbox isn't axis aligned, so we must construct one +// should this be cached in the selection manager? yes. +LLBBox get_selection_axis_aligned_bbox() +{ + LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); + LLVector3 position = selection_bbox.getPositionAgent(); + + LLBBox axis_aligned_bbox = LLBBox(position, LLQuaternion(), LLVector3(), LLVector3()); + axis_aligned_bbox.addPointLocal(LLVector3()); + + // cycle over the nodes in selection + for (LLObjectSelection::iterator selection_iter = LLSelectMgr::getInstance()->getSelection()->begin(); + selection_iter != LLSelectMgr::getInstance()->getSelection()->end(); + ++selection_iter) + { + LLSelectNode *select_node = *selection_iter; + if (select_node) + { + LLViewerObject* object = select_node->getObject(); + if (object) + { + axis_aligned_bbox.addBBoxAgent(object->getBoundingBoxAgent()); + } + } + } + + + return axis_aligned_bbox; +} + + + +void QToolAlign::computeManipulatorSize() +{ + if (LLSelectMgr::getInstance()->getSelection()->getSelectType() == SELECT_TYPE_HUD) + { + mManipulatorSize = MANIPULATOR_SIZE / (LLViewerCamera::getInstance()->getViewHeightInPixels() * + gAgent.mHUDCurZoom); + } + else + { + F32 distance = dist_vec(gAgent.getCameraPositionAgent(), mBBox.getCenterAgent()); + + if (distance > 0.001f) + { + // range != zero + F32 fraction_of_fov = MANIPULATOR_SIZE /LLViewerCamera::getInstance()->getViewHeightInPixels(); + F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView(); // radians + mManipulatorSize = MANIPULATOR_SIZE * distance * tan(apparent_angle); + } + else + { + // range == zero + mManipulatorSize = MANIPULATOR_SIZE; + } + } +} + + +LLColor4 manipulator_color[3] = { LLColor4(0.7f, 0.0f, 0.0f, 0.5f), + LLColor4(0.0f, 0.7f, 0.0f, 0.5f), + LLColor4(0.0f, 0.0f, 0.7f, 0.5f) }; + + +void QToolAlign::renderManipulators() +{ + computeManipulatorSize(); + LLVector3 bbox_center = mBBox.getCenterAgent(); + LLVector3 bbox_scale = mBBox.getMaxLocal() - mBBox.getMinLocal(); + + for (S32 axis = VX; axis <= VZ; axis++) + for (F32 direction = -1.0; direction <= 1.0; direction += 2.0) + { + F32 size = mManipulatorSize; + LLColor4 color = manipulator_color[axis]; + + if ((axis == mHighlightedAxis) && (direction == mHighlightedDirection)) + { + size *= 2.0; + color *= 1.5; + } + + S32 arrows = 1; + if (mForce) + { + arrows = 2; + } + + for (S32 i = 0; i < arrows; i++) + { + LLVector3 axis_vector = LLVector3(0,0,0); + axis_vector.mV[axis] = direction * (bbox_scale.mV[axis] / 2.0 + i * (size/3.0)); + + LLVector3 manipulator_center = bbox_center + axis_vector; + + LLQuaternion manipulator_rotation; + manipulator_rotation.shortestArc(LLVector3(0,0,1), -1.0 * axis_vector); + + LLBBox manipulator_bbox = LLBBox(manipulator_center, manipulator_rotation, + LLVector3(), LLVector3()); + + manipulator_bbox.addPointLocal(LLVector3(-1, -1, -0.75) * size * 0.5); + manipulator_bbox.addPointLocal(LLVector3(1, 1, 0.75) * size * 0.5); + + gGL.color4fv(color.mV); + // sadly, gCone doesn't use gGL like gBox does (presumably because its author smokes crack) so we + // also set the raw GL color. hopefully this won't screw-up later rendering. + glColor4fv(color.mV); + + render_cone_bbox(manipulator_bbox); + } + } +} + + +void QToolAlign::render() +{ + mBBox = get_selection_axis_aligned_bbox(); + + // Draw bounding box + LLGLSUIDefault gls_ui; + LLGLEnable gl_blend(GL_BLEND); + LLGLEnable gls_alpha_test(GL_ALPHA_TEST); + LLGLDepthTest gls_depth(GL_FALSE); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + // render box + LLColor4 default_normal_color( 0.7f, 0.7f, 0.7f, 0.1f ); + gGL.color4fv( default_normal_color.mV ); + + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getEditSelection(); + BOOL can_move = selection->getObjectCount() != 0; + if (can_move) + { + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* objectp) + { + return objectp->permMove() && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts")); + } + } func; + can_move = selection->applyToObjects(&func); + } + if (can_move) + { + render_bbox(mBBox); + renderManipulators(); + } +} + +// only works for our specialized (AABB, position centered) bboxes +BOOL bbox_overlap(LLBBox bbox1, LLBBox bbox2) +{ + const F32 FUDGE = 0.001f; // because of stupid SL precision/rounding + + LLVector3 delta = bbox1.getCenterAgent() - bbox2.getCenterAgent(); + + LLVector3 half_extent = (bbox1.getExtentLocal() + bbox2.getExtentLocal()) / 2.0; + + return ((fabs(delta.mV[VX]) < half_extent.mV[VX] - FUDGE) && + (fabs(delta.mV[VY]) < half_extent.mV[VY] - FUDGE) && + (fabs(delta.mV[VZ]) < half_extent.mV[VZ] - FUDGE)); +} + + + +// used to sort bboxes before packing +class BBoxCompare +{ +public: + BBoxCompare(S32 axis, F32 direction, std::map<LLPointer<LLViewerObject>, LLBBox >& bboxes) : + mAxis(axis), mDirection(direction), mBBoxes(bboxes) {} + + BOOL operator() (LLViewerObject* object1, LLViewerObject* object2) + { + LLVector3 corner1 = mBBoxes[object1].getCenterAgent() - + mDirection * mBBoxes[object1].getExtentLocal()/2.0; + + LLVector3 corner2 = mBBoxes[object2].getCenterAgent() - + mDirection * mBBoxes[object2].getExtentLocal()/2.0; + + + return mDirection * corner1.mV[mAxis] < mDirection * corner2.mV[mAxis]; + } + + S32 mAxis; + F32 mDirection; + std::map<LLPointer<LLViewerObject>, LLBBox >& mBBoxes; +}; + + +void QToolAlign::align() +{ + // no linkset parts, please + LLSelectMgr::getInstance()->promoteSelectionToRoot(); + + std::vector<LLPointer<LLViewerObject> > objects; + std::map<LLPointer<LLViewerObject>, LLBBox > original_bboxes; + + // cycle over the nodes in selection and collect them into an array + for (LLObjectSelection::root_iterator selection_iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + selection_iter != LLSelectMgr::getInstance()->getSelection()->root_end(); + ++selection_iter) + { + LLSelectNode *select_node = *selection_iter; + if (select_node) + { + LLViewerObject* object = select_node->getObject(); + if (object) + { + LLVector3 position = object->getPositionAgent(); + + LLBBox bbox = LLBBox(position, LLQuaternion(), LLVector3(), LLVector3()); + bbox.addPointLocal(LLVector3()); + + // add the parent's bbox + bbox.addBBoxAgent(object->getBoundingBoxAgent()); + LLViewerObject::const_child_list_t& children = object->getChildren(); + + for (LLViewerObject::const_child_list_t::const_iterator i = children.begin(); + i != children.end(); i++) + { + // add the child's bbox + LLViewerObject* child = *i; + bbox.addBBoxAgent(child->getBoundingBoxAgent()); + } + + objects.push_back(object); + original_bboxes[object] = bbox; + } + } + } + + S32 axis = mHighlightedAxis; + F32 direction = mHighlightedDirection; + + // sort them into positional order for proper packing + BBoxCompare compare(axis, direction, original_bboxes); + sort(objects.begin(), objects.end(), compare); + + // storage for their new position after alignment - start with original position first + std::map<LLPointer<LLViewerObject>, LLBBox > new_bboxes = original_bboxes; + + // find new positions + for (S32 i = 0; i < (S32)objects.size(); i++) + { + LLBBox target_bbox = mBBox; + LLVector3 target_corner = target_bbox.getCenterAgent() - + direction * target_bbox.getExtentLocal() / 2.0; + + LLViewerObject* object = objects[i]; + + LLBBox this_bbox = original_bboxes[object]; + LLVector3 this_corner = this_bbox.getCenterAgent() - + direction * this_bbox.getExtentLocal() / 2.0; + + // for packing, we cycle over several possible positions, taking the smallest that does not overlap + F32 smallest = direction * 9999999; // 999999 guarenteed not to be the smallest + for (S32 j = 0; j <= i; j++) + { + // how far must it move? + LLVector3 delta = target_corner - this_corner; + + // new position moves only on one axis, please + LLVector3 delta_one_axis = LLVector3(0,0,0); + delta_one_axis.mV[axis] = delta.mV[axis]; + + LLVector3 new_position = this_bbox.getCenterAgent() + delta_one_axis; + + // construct the new bbox + LLBBox new_bbox = LLBBox(new_position, LLQuaternion(), LLVector3(), LLVector3()); + new_bbox.addPointLocal(this_bbox.getExtentLocal() / 2.0); + new_bbox.addPointLocal(-1.0 * this_bbox.getExtentLocal() / 2.0); + + // check to see if it overlaps the previously placed objects + BOOL overlap = FALSE; + + llwarns << "i=" << i << " j=" << j << llendl; + + if (!mForce) // well, don't check if in force mode + { + for (S32 k = 0; k < i; k++) + { + LLViewerObject* other_object = objects[k]; + LLBBox other_bbox = new_bboxes[other_object]; + + BOOL overlaps_this = bbox_overlap(other_bbox, new_bbox); + + if (overlaps_this) + { + llwarns << "overlap" << new_bbox.getCenterAgent() << other_bbox.getCenterAgent() << llendl; + llwarns << "extent" << new_bbox.getExtentLocal() << other_bbox.getExtentLocal() << llendl; + } + + overlap = (overlap || overlaps_this); + } + } + + if (!overlap) + { + F32 this_value = (new_bbox.getCenterAgent() - + direction * new_bbox.getExtentLocal() / 2.0).mV[axis]; + + if (direction * this_value < direction * smallest) + { + smallest = this_value; + // store it + new_bboxes[object] = new_bbox; + } + } + + // update target for next time through the loop + if (j < (S32)objects.size()) + { + LLBBox next_bbox = new_bboxes[objects[j]]; + target_corner = next_bbox.getCenterAgent() + + direction * next_bbox.getExtentLocal() / 2.0; + } + } + } + + + // now move them + for (S32 i = 0; i < (S32)objects.size(); i++) + { + LLViewerObject* object = objects[i]; + + LLBBox original_bbox = original_bboxes[object]; + LLBBox new_bbox = new_bboxes[object]; + + LLVector3 delta = new_bbox.getCenterAgent() - original_bbox.getCenterAgent(); + + LLVector3 original_position = object->getPositionAgent(); + LLVector3 new_position = original_position + delta; + + object->setPosition(new_position); + } + + + LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); +} + + diff --git a/linden/indra/newview/qtoolalign.h b/linden/indra/newview/qtoolalign.h new file mode 100644 index 000000000..b2c18b7da --- /dev/null +++ b/linden/indra/newview/qtoolalign.h @@ -0,0 +1,50 @@ +/** + * @file qtoolalign.h + * @brief A tool to align objects + * @author Karl Stiefvater (Qarl) + * + * Karl has given permission to use this code under the terms of + * the GNU GPL v2 plus FLOSS exception and/or the GNU LGPL v2.1. + * + * Backported for Viewer 1.X code base by Jacek Antonelli. + */ + +#ifndef Q_QTOOLALIGN_H +#define Q_QTOOLALIGN_H + +#include "lltool.h" +#include "llbbox.h" + +class LLViewerObject; +class LLPickInfo; +class LLToolSelectRect; + +class QToolAlign +: public LLTool, public LLSingleton<QToolAlign> +{ +public: + QToolAlign(); + virtual ~QToolAlign(); + + virtual void handleSelect(); + virtual void handleDeselect(); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual void render(); + + static void pickCallback(const LLPickInfo& pick_info); + +private: + void align(); + void computeManipulatorSize(); + void renderManipulators(); + BOOL findSelectedManipulator(S32 x, S32 y); + + LLBBox mBBox; + F32 mManipulatorSize; + S32 mHighlightedAxis; + F32 mHighlightedDirection; + BOOL mForce; +}; + +#endif // Q_QTOOLALIGN_H diff --git a/linden/indra/newview/secondlife-i686.supp b/linden/indra/newview/secondlife-i686.supp index 43d448346..d70cda3b8 100644 --- a/linden/indra/newview/secondlife-i686.supp +++ b/linden/indra/newview/secondlife-i686.supp @@ -41,50 +41,6 @@ # - After you build the viewer, replace the stripped # do-not-directly-run-secondlife-bin binary with an unstripped copy. -# Mozilla noise. - -{ - Cond:mozilla-runtime/*.so - Memcheck:Cond - obj:*/mozilla-runtime-*/*.so -} - -{ - Value4:mozilla-runtime/*.so - Memcheck:Value4 - obj:*/mozilla-runtime-*/*.so -} - -{ - Cond:mozilla-runtime/*/*.so - Memcheck:Cond - obj:*/mozilla-runtime-*/*/*.so -} - -{ - Value4:mozilla-runtime/*/*.so - Memcheck:Value4 - obj:*/mozilla-runtime-*/*/*.so -} - -{ - Cond:mozilla-runtime/libmozjs.so - Memcheck:Cond - obj:*/libmozjs.so -} - -{ - Cond:mozilla-runtime/libxul - Memcheck:Cond - obj:*/libxul.so -} - -{ - Value4:mozilla-runtime/libxul - Memcheck:Value4 - obj:*/libxul.so -} - # libcurl badness. { diff --git a/linden/indra/newview/skins/default/html/en-us/loading/loading.html b/linden/indra/newview/skins/default/html/en-us/loading/loading.html deleted file mode 100644 index 97174b017..000000000 --- a/linden/indra/newview/skins/default/html/en-us/loading/loading.html +++ /dev/null @@ -1,9 +0,0 @@ -<body style="background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;"> -<table width="100%" height="100%" border="0"> - <tr> - <td align="center" valign="middle" style="font-size:0.8em;"> - <img src="imprudence_loading.png" align="absmiddle"><br/>   loading... - </td> - </tr> -</table> -</body> diff --git a/linden/indra/newview/skins/default/textures/textures.xml b/linden/indra/newview/skins/default/textures/textures.xml index 0b4a08867..60fb4e062 100644 --- a/linden/indra/newview/skins/default/textures/textures.xml +++ b/linden/indra/newview/skins/default/textures/textures.xml @@ -16,7 +16,9 @@ <texture name="toolbar_btn_selected.tga" scale_left="7" scale_top="32" scale_right="121" scale_bottom="0" /> <texture name="button_enabled_selected_32x128.tga" preload="true" scale_left="16" scale_top="16" scale_right="112" scale_bottom="16" /> - + + <texture name="media_panel_bg.png" preload="true" scale_left="9" scale_top="9" scale_right="9" scale_bottom="9" /> + <texture name="media_panel_hoverrectangle.png" preload="true" scale_left="9" scale_top="9" scale_right="9" scale_bottom="9" /> <texture name="checkbox_disabled_false.tga" preload="true"/> <texture name="checkbox_disabled_true.tga" preload="true"/> <texture name="checkbox_enabled_false.tga" preload="true"/> @@ -376,7 +378,24 @@ <texture name="default_profile_picture.j2c"/> <texture name="locked_image.j2c"/> + <!-- Kitty Viewer Art --> <texture name="Inv_WindLight" file_name="Inv_WindLight.png" preload="false" /> <texture name="Inv_WaterLight" file_name="Inv_WaterLight.png" preload="false" /> + + <texture name="media_btn_back.png"/> + <texture name="media_btn_done.png"/> + <texture name="media_btn_forward.png"/> + <texture name="media_btn_home.png"/> + <texture name="media_btn_newwindow.png"/> + <texture name="media_btn_optimalzoom.png"/> + <texture name="media_btn_reload.png"/> + <texture name="media_btn_scrolldown.png"/> + <texture name="media_btn_scrollleft.png"/> + <texture name="media_btn_scrollright.png"/> + <texture name="media_btn_scrollup.png"/> + <texture name="media_btn_stoploading.png"/> + <texture name="media_panel_divider.png"/> + <texture name="media_panel_scrollbg.png"/> + </textures> diff --git a/linden/indra/newview/skins/default/xui/de/floater_command_line.xml b/linden/indra/newview/skins/default/xui/de/floater_command_line.xml new file mode 100644 index 000000000..e3b2ec31a --- /dev/null +++ b/linden/indra/newview/skins/default/xui/de/floater_command_line.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater name="busy" title="Chatleisten-Befehle"> + <text name="loltxt2"> Innerhalb des Sims teleportieren (Nutzung: cmd x y z)</text> + <line_editor tool_tip="" name="CmdLineChatbarPos"/> + <text name="loltxt3"> Zum Boden teleportieren (Nutzung: cmd)</text> + <line_editor tool_tip="" name="CmdLineChatbarGround"/> + <text name="loltxt4"> In Höhe teleportieren (Nutzung: cmd z)</text> + <line_editor tool_tip="" name="CmdLineChatbarHeight"/> + <text name="loltxt5"> Nach Hause teleportieren (Nutzung: cmd)</text> + <line_editor tool_tip="" name="CmdLineChatbarTeleportHome"/> + <text name="loltxt6"> Eine Plattform schaffen (Nutzung: cmd 0 - 30)</text> + <line_editor tool_tip="" name="CmdLineChatbarRezPlatform"/> + <slider name="CmdLineChatbarPlatformSize" label="Breite" tool_tip="Wie groß soll die Plattform sein?"/> + <text name="loltxt7"> Zu Sim x teleportieren (Nutzung: cmd simname)</text> + <line_editor tool_tip="" name="CmdLineChatbarMapTo"/> + <check_box label="Gleiche Position nutzen" name="toggle"/> + <text name="loltxt8"> math. Ausdruck rechnen (Nutzung: cmd SIN(2+2))</text> + <line_editor tool_tip="" name="CmdLineChatbarCalc"/> + <text name="add_autokorrect">Wort zu Autokorrekt zufügen(Nutzung: cmd list|bad|good)</text> + <line_editor tool_tip="" name="CmdLineChatbarAutocorrect"/> + <text name="loltxt9"> Sichtweite ändern (Nutzung: cmd meters)</text> + <line_editor tool_tip="" name="CmdLineChatbarDrawDistance"/> + <text name="loltxt10"> Zur Kameraposition teleportieren (Nutzung: cmd)</text> + <line_editor tool_tip="" name="CmdLineChatbarTeleportToCam"/> + <text name="loltxt11"> Avatarname von Schlssel beziehen (Nutzung: cmd key)</text> + <line_editor tool_tip="" name="CmdLineChatbarKeyToName"/> + <text name="loltxt12"> Avatar Teleport anbieten (Nutzung: cmd key)</text> + <line_editor tool_tip="" name="CmdLineChatbarOfferTp"/> + <text name="loltxt13"> Zu Avatar teleportieren (Nutzung: cmd name)</text> + <line_editor tool_tip="Die syntax dieses Befehls erlaubt partielle Namen (ohne Groß-/Kleinschreibung). Bessere Resultate bei Nutzung mit offenem Radar." + name="CmdLineChatbarTP2"/> + <text name="loltxt14"> AO an/aus (Nutzung: cmd on/off)</text> + <line_editor tool_tip="" name="CmdLineChatbarAO"/> + <text name="loltxt15"> Chat-Historie löschen (Nutzung: cmd)</text> + <line_editor tool_tip="Löscht die Chat-Historie, um Lag-Effekte von Chat-Spammern zu verhindern." name="CmdLineChatbarClearChat"/> + <text name="loltxt15"> Medien-URL bestimmen (Nutzung: cmd url type)</text> + <line_editor tool_tip="Bestimmt und spielt Ihren Medienstrom auf die eingegebene URL" name="CmdLineChatbarMedia"/> + <text name="loltxt15"> Musik-URL bestimmen (Nutzung: cmd url)</text> + <line_editor tool_tip="Bestimmt und spielt Ihren Musikstrom auf die eingegebene URL" name="CmdLineChatbarMusic"/> + <button label="?" name="Help_CmdLine" +tool_tip="Hier für Hilfe betreffend der Einstellungen dieser Seite klicken."/> +</floater> \ No newline at end of file diff --git a/linden/indra/newview/skins/default/xui/de/floater_lagmeter.xml b/linden/indra/newview/skins/default/xui/de/floater_lagmeter.xml index 4dd9fd6c7..f49fccae0 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_lagmeter.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_lagmeter.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater name="floater_lagmeter" title="Lag-Anzeige"> - <button name="client_lagmeter" tool_tip="Client-Lag-Status" /> + <button name="client_lagmeter" tool_tip="Lag-Status Client" /> <text name="client"> Client: </text> @@ -14,7 +14,7 @@ <text name="network_text"> Normal </text> - <button name="server_lagmeter" tool_tip="Server-Lag-Status" /> + <button name="server_lagmeter" tool_tip="Lag-Status Server" /> <text name="server"> Server: </text> @@ -27,7 +27,7 @@ Lag-Anzeige </text> <text name="max_width_px"> - 350 + 360 </text> <text name="min_title_msg"> Lag @@ -48,10 +48,10 @@ Normal, Fenster im Hintergrund </text> <text name="client_frame_time_critical_msg"> - Client-Frame-Rate unter [CLIENT_FRAME_RATE_CRITICAL] + Frame-Rate Client unter [CLIENT_FRAME_RATE_CRITICAL] </text> <text name="client_frame_time_warning_msg"> - Client-Frame-Rate zwischen [CLIENT_FRAME_RATE_CRITICAL] und [CLIENT_FRAME_RATE_WARNING] + Frame-Rate Client zwischen [CLIENT_FRAME_RATE_CRITICAL] und [CLIENT_FRAME_RATE_WARNING] </text> <text name="client_frame_time_normal_msg"> Normal @@ -117,10 +117,10 @@ 20 </text> <text name="server_frame_time_critical_msg"> - Simulator-Frame-Rate liegt unter [SERVER_FRAME_RATE_CRITICAL] + Frame-Rate Simulator liegt unter [SERVER_FRAME_RATE_CRITICAL] </text> <text name="server_frame_time_warning_msg"> - Simulator-Frame-Rate liegt zwischen [SERVER_FRAME_RATE_CRITICAL] und [SERVER_FRAME_RATE_WARNING] + Frame-Rate Simulator liegt zwischen [SERVER_FRAME_RATE_CRITICAL] und [SERVER_FRAME_RATE_WARNING] </text> <text name="server_frame_time_normal_msg"> Normal diff --git a/linden/indra/newview/skins/default/xui/de/floater_local_asset_browse.xml b/linden/indra/newview/skins/default/xui/de/floater_local_asset_browse.xml new file mode 100644 index 000000000..45a19baa6 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/de/floater_local_asset_browse.xml @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<!-- Local Asset Browser: xui --> +<!-- floater definition start --> + +<floater + name="local_bitmap_browser_floater" + title="Lokal Textur-Eigenschaften" + > + + <button + name="add_btn" + label="Hinzufügen" + /> + <button + name="del_btn" + label="Entfernen" + /> + <button + name="upload_btn" + label="Bild hochladen ([UPLOADFEE])..." + /> + + <scroll_list + name="bitmap_list" + > + <column name="bitmap_name" label="Name" dynamicwidth="true" /> + <column name="bitmap_uuid" label="UUID" width="240" /> + </scroll_list> + + <text name="path_caption_text" + > + Lokaler Pfad: + </text> + + <text name="uuid_caption_text" + > + Lokale UUID: + </text> + + <texture_picker + label="Textur" + name="texture_view" + /> + + <check_box + label="Aktualisierungscheck" + name="keep_updating_checkbox" + tool_tip="Periodische Checks ein- oder ausschalten, ob die Quelle auf der Festplatte aktualisiert wurde" + /> + + <combo_box + name="type_combobox" + > + + <combo_item name="type_texture" value="type_texture"> + Textur + </combo_item> + + <combo_item name="type_sculptie" value="type_sculptie"> + Sculptmap + </combo_item> + + <combo_item name="type_layer" value="type_layer"> + Kleidung + </combo_item> + + </combo_box> + + <text name="time_caption_text" + > + Zeit: + </text> + + <text name="time_text" + > + (Hier Datum) + </text> + + <text name="link_caption_text" + > + Link: + </text> + + <text name="link_text" + > + (Linkstatus) + </text> + + <text name="name_caption_text" + > + Name: + </text> + +</floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_media_browser.xml b/linden/indra/newview/skins/default/xui/de/floater_media_browser.xml index ee2532127..3bc231ac0 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_media_browser.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_media_browser.xml @@ -6,13 +6,17 @@ <button label="Weiter" name="forward" /> <button label="Neu laden" name="reload" /> <button label="Los" name="go" /> + <button label="Zuhause" name="home" /> </layout_panel> <layout_panel name="parcel_owner_controls"> + <web_browser name="browser" /> <button label="Aktuelle URL an Parzelle senden" name="assign" /> </layout_panel> <layout_panel name="external_controls"> <button label="In meinem Browser öffnen" name="open_browser" /> <check_box label="Immer in meinem Browser öffnen" name="open_always" /> + <button label="Als Zuhause setzen" name="set_home" /> + <button label="Schließen" name="close" /> </layout_panel> </layout_stack> diff --git a/linden/indra/newview/skins/default/xui/de/floater_mini_map.xml b/linden/indra/newview/skins/default/xui/de/floater_mini_map.xml index d38925817..232ec3e31 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_mini_map.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_mini_map.xml @@ -1,4 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="minimap"> +<floater name="minimap" short_title="Mini-Karte"> <panel label="Minikarte" name="mini_mapview" tool_tip="(Karte mit Doppelklick öffnen)"/> + <!-- Note: panel contents are defined in panel_radar.xml --> + <panel name="RadarPanel" label="Radar" /> + <button name="toggle_radar" label="" tool_tip="Radar anzeigen oder verstecken" /> + </floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_mute.xml b/linden/indra/newview/skins/default/xui/de/floater_mute.xml index 5dbb9fc6e..b39c97ac7 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_mute.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_mute.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater name="mute floater" title="Stummgeschaltete Einwohner und Objekte" short_title="Stummschalten-Liste"> - <scroll_list name="mutes" tool_tip="List of currently muted residents" /> +<floater name="mute floater" title="Stummgeschaltete Einwohner & Objekte" short_title="Stummschalten-Liste"> + <scroll_list name="mutes" tool_tip="Liste derzeit stummgeschalteter Einwohner" /> <button label="Einwohner stummschalten..." label_selected="Einwohner stummschalten..." name="Mute resident..." tool_tip="Wählen Sie einen Einwohner, um ihn stumm zu schalten" /> diff --git a/linden/indra/newview/skins/default/xui/de/floater_mute_object.xml b/linden/indra/newview/skins/default/xui/de/floater_mute_object.xml index 60c6ff008..bf6059f39 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_mute_object.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_mute_object.xml @@ -2,7 +2,7 @@ <floater name="mute by name" title="Objekt nach Name stummschalten"> <text name="message"> Stummschalten nach Name betrifft nur Chat und IM, keine -Sounds. Sie müssen den Objektnamen exakt angeben. +Klänge. Sie müssen den Objektnamen exakt eingeben. </text> <line_editor name="object_name"> Objektname diff --git a/linden/indra/newview/skins/default/xui/de/floater_name_description.xml b/linden/indra/newview/skins/default/xui/de/floater_name_description.xml index f45b1e0b3..608c3eb7a 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_name_description.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_name_description.xml @@ -7,5 +7,5 @@ Beschreibung: </text> <button label="Abbrechen" name="cancel_btn" width="80" /> - <button label="Hochladen ([AMOUNT] L$)" name="ok_btn" width="120" /> + <button label="Hochladen ([UPLOADFEE])" name="ok_btn" width="120" /> </floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_new_outfit_dialog.xml b/linden/indra/newview/skins/default/xui/de/floater_new_outfit_dialog.xml index 73c6760be..dbb96ef2c 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_new_outfit_dialog.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_new_outfit_dialog.xml @@ -16,6 +16,9 @@ <check_box label="Unterhemd" name="checkbox_Undershirt" left="90"/> <check_box label="Unterhose" name="checkbox_Underpants" left="90"/> <check_box label="Rock" name="checkbox_Skirt" left="90"/> + <check_box label="Tätowierung" name="checkbox_Tattoo" left="90"/> + <check_box label="Transparenz" name="checkbox_Alpha" left="90"/> + <check_box label="Brust" name="checkbox_Chest" left="190"/> <check_box label="Schädel" name="checkbox_Skull" left="190"/> <check_box label="Linke Schulter" name="checkbox_Left Shoulder" left="190"/> @@ -59,9 +62,8 @@ </text> <text type="string" length="1" name="Outfits are folders that contain clothing and body parts. Drag an outfit folder onto your avatar to put it on. "Make New Outfit" makes a new folder and saves copies of the items you are now wearing into it."> - Outfits sind Ordner, die Kleider und Körperteile enthalten. -Ziehen Sie einen Outfit-Ordner auf Ihren Avatar, um ihn anzuziehen. - + Outfits sind Ordner, die Kleidung und Körperteile enthalten. Ziehen Sie einen Outfit-Ordner auf Ihren Avatar, um ihn anzuziehen. + „Neues Outfit“ erstellt einen neuen Ordner und speichert darin Kopien der Objekte, die Sie gerade tragen. </text> diff --git a/linden/indra/newview/skins/default/xui/de/floater_notifications_console.xml b/linden/indra/newview/skins/default/xui/de/floater_notifications_console.xml index a1cd69899..14318dd9e 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_notifications_console.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_notifications_console.xml @@ -2,4 +2,7 @@ <floater name="notifications_console" title="Konsole: Meldungen"> <combo_box label="Meldungsart auswählen" name="notification_types" width="412" /> <button label="Hinzufügen" name="add_notification" left="417" width="78" /> + <button name="reload_notifications" left="497" width="85" label="Alle Neuladen"/> + <layout_stack name="notification_channels"> + </layout_stack> </floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_pay.xml b/linden/indra/newview/skins/default/xui/de/floater_pay.xml index dc38697fe..a98894d60 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_pay.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_pay.xml @@ -5,10 +5,10 @@ Schnellzahlung: </text> - <button name="fastpay 1" label="1 L$" left="115" /> - <button name="fastpay 5" label="5 L$" /> - <button name="fastpay 10" label="10 L$" left="115" /> - <button name="fastpay 20" label="20 L$" /> + <button name="fastpay 1" label="1 [CURRENCY]" left="115" /> + <button name="fastpay 5" label="5 [CURRENCY]" /> + <button name="fastpay 10" label="10 [CURRENCY]" left="115" /> + <button name="fastpay 20" label="20 [CURRENCY]" /> <text name="amount text"> Betrag: diff --git a/linden/indra/newview/skins/default/xui/de/floater_pay_object.xml b/linden/indra/newview/skins/default/xui/de/floater_pay_object.xml index 55ad7352b..07dee3717 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_pay_object.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_pay_object.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater name="Give Money"> +<floater name="Give Money" title="[PAY TYPE] [FIRST] [LAST> <string name="pay group"> Gruppe bezahlen: @@ -16,14 +16,17 @@ Schnellzahlung: </text> - <button name="fastpay 1" label="1 L$" left="115" /> - <button name="fastpay 5" label="5 L$" /> - <button name="fastpay 10" label="10 L$" left="115" /> - <button name="fastpay 20" label="20 L$" /> + <button name="fastpay 1" label="1 [CURRENCY]" left="115" /> + <button name="fastpay 5" label="5 [CURRENCY]" /> + <button name="fastpay 10" label="10 [CURRENCY]" left="115" /> + <button name="fastpay 20" label="20 [CURRENCY]" /> <text name="amount text"> Betrag: </text> + <text name="currency text"> + [CURRENCY] + </text> <button name="pay btn" label="Zahlen" /> <button name="cancel btn" label="Abbrechen" /> diff --git a/linden/indra/newview/skins/default/xui/de/floater_post_process.xml b/linden/indra/newview/skins/default/xui/de/floater_post_process.xml index e10806d25..4baad6927 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_post_process.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_post_process.xml @@ -32,16 +32,16 @@ Rauschen-Stärke </text> </panel> - <panel label="Bloom" name="wmiBloomPanel"> + <panel label="Schleier" name="wmiBloomPanel"> <check_box label="Ein" name="wmiBloomToggle" /> <text name="wmiBloomExtractText"> Luminanz-Extraktion </text> <text name="wmiBloomSizeText"> - Bloom-Größe + Schleier-Größe </text> <text name="wmiBloomStrengthText"> - Bloom-Stärke + Schleier-Stärke </text> </panel> <panel label="Extras" name="Extras"> diff --git a/linden/indra/newview/skins/default/xui/de/floater_postcard.xml b/linden/indra/newview/skins/default/xui/de/floater_postcard.xml index 639a8ffdd..90a3c3d41 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_postcard.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_postcard.xml @@ -22,18 +22,11 @@ <text_editor name="msg_form"> Nachricht hier eingeben. </text_editor> - <check_box label="Im Web veröffentlichen" name="allow_publish_check" - tool_tip="Veröffentlicht diese Postkarte im Web." /> - <check_box label="Ab-18-Inhalt" name="mature_check" - tool_tip="Diese Postkarte enthält nicht jugendfreie Inhalte." /> - <button label="?" name="publish_help_btn" /> - <text name="fine_print"> - Wenn sich der Empfänger bei SL anmeldet, erhalten Sie einen Empfehlungsbonus. - </text> + <button label="Abbrechen" name="cancel_btn" /> <button label="Senden" name="send_btn" /> <text name="default_subject"> - Postkarte aus Second Life. + Postkarte aus [GRID_NAME]. </text> <text name="default_message"> Sehen Sie hier! diff --git a/linden/indra/newview/skins/default/xui/de/floater_preferences.xml b/linden/indra/newview/skins/default/xui/de/floater_preferences.xml index 5f68282b9..ac18f2880 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_preferences.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_preferences.xml @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater name="Preferences" title="Einstellungen"> +<floater name="Preferences" title="Voreinstellungen"> <button label="OK" label_selected="OK" name="OK" /> <button label="Abbrechen" label_selected="Abbrechen" name="Cancel" /> <button label="Übernehmen" label_selected="Übernehmen" name="Apply" /> - <button label="Info" label_selected="Info" name="About..." /> <button label="Hilfe" label_selected="Hilfe" name="Help" /> </floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_preview_notecard.xml b/linden/indra/newview/skins/default/xui/de/floater_preview_notecard.xml index 370f242dd..7925ed6f9 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_preview_notecard.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_preview_notecard.xml @@ -1,16 +1,40 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater name="preview notecard" title="Hinweis:"> - <button label="Speichern" label_selected="Speichern" name="Save" /> <text type="string" length="1" name="desc txt"> Beschreibung: </text> + + <menu_bar name="motecard_menu"> + <menu name="File"> + <menu_item_call label="Speichern" name="Save Menu" shortcut="control|S" /> + <menu_item_separator /> + <menu_item_call label="Text Exportieren..." name="Export Text..." /> + <menu_item_call label="Text Importieren..." name="Import Text..." /> + </menu> + <menu name="Edit"> + <menu_item_call label="Rückgängig" name="Undo" /> + <menu_item_call label="Wiederherstellen" name="Redo" width="139" /> + <menu_item_separator label="-----------" name="separator1" width="139" /> + <menu_item_call label="Ausschneiden" name="Cut" /> + <menu_item_call label="Kopieren" name="Copy" /> + <menu_item_call label="Einfügen" name="Paste" /> + <menu_item_separator label="-----------" name="separator2" width="139" /> + <menu_item_call label="Alle auswählen" name="Select All" width="139" /> + <menu_item_call label="Deselektieren" name="Deselect" width="139" /> + <menu_item_separator label="-----------" name="separator3" width="139" /> + <menu_item_call label="Suchen / Ersetzen..." + name="Search / Replace..." width="139" /> + </menu> + </menu_bar> + <text_editor type="string" length="1" name="Notecard Editor"> Wird geladen... </text_editor> - <text name="no_object"> + <button label="Sichern" label_selected="Sichern" name="Save" /> + <string name="no_object"> Es wurde kein Objekt gefunden, das diese Notiz enthält. - </text> - <text name="not_allowed"> + </string> + <string name="not_allowed"> Sie können diese Notiz nicht anzeigen. - </text> + </string> </floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_preview_notecard_keep_discard.xml b/linden/indra/newview/skins/default/xui/de/floater_preview_notecard_keep_discard.xml index 1faf82bc6..7d068fe07 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_preview_notecard_keep_discard.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_preview_notecard_keep_discard.xml @@ -1,16 +1,39 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater name="preview_notecard"> - <text_editor type="string" length="1" name="Notecard Editor"> - Wird geladen... - </text_editor> +<floater name="preview_notecard" title="Notiz:" > <text type="string" length="1" name="desc txt"> Beschreibung: </text> + <menu_bar name="motecard_menu"> + <menu name="File"> + <menu_item_call label="Sichern" name="Save Menu" /> + <menu_item_separator /> + <menu_item_call label="Text Exportieren..." name="Export Text..." /> + <menu_item_call label="Text Importieren..." name="Import Text..." /> + </menu> + <menu name="Edit"> + <menu_item_call label="Rückgängig" name="Undo" width="139" /> + <menu_item_call label="Wiederherstellen" name="Redo" width="139" /> + <menu_item_separator label="-----------" name="separator1" width="139" /> + <menu_item_call label="Ausschneiden" name="Cut" width="139" /> + <menu_item_call label="Kopieren" name="Copy" width="139" /> + <menu_item_call label="Einfügen" name="Paste" width="139" /> + <menu_item_separator label="-----------" name="separator2" width="139" /> + <menu_item_call label="Alle auswählen" name="Select All" width="139" /> + <menu_item_call label="Deselektieren" name="Deselect" width="139" /> + <menu_item_separator label="-----------" name="separator3" width="139" /> + <menu_item_call label="Suchen / Ersetzen..." + name="Search / Replace..." width="139" /> + </menu> + </menu_bar> + <text_editor type="string" length="1" name="Notecard Editor"> + Wird geladen... + </text_editor> <button label="Behalten" label_selected="Behalten" name="Keep" /> + <button label="Sichern" label_selected="Sichern" name="Save" /> <button label="Verwerfen" label_selected="Verwerfen" name="Discard" /> - <text name="no_object"> - Es wurde kein Objekt gefunden, das diese Notiz enthält: - </text> + <string name="no_object"> + Es wurde kein Objekt gefunden, das diese Notiz enthält. + </string> <string name="not_allowed"> Sie können diese Notiz nicht anzeigen. </string> diff --git a/linden/indra/newview/skins/default/xui/de/floater_preview_sound.xml b/linden/indra/newview/skins/default/xui/de/floater_preview_sound.xml index fd0a824c0..64e3e565d 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_preview_sound.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_preview_sound.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater name="preview_sound"> +<floater name="preview_sound" width="310"> <text type="string" length="1" name="desc txt"> Beschreibung: </text> @@ -8,5 +8,5 @@ tool_tip="Gibt diesen Sound so wieder, dass andere ihn hören können." /> <button label="Lokal wiedergeben" label_selected="Lokal wiedergeben" name="Sound audition btn" - tool_tip="Gibt diesen Sound so wieder, dass nur Sie ihn hören." /> + tool_tip="Gibt diesen Sound so wieder, dass nur Sie ihn hören." width="130" /> </floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_prim_import.xml b/linden/indra/newview/skins/default/xui/de/floater_prim_import.xml new file mode 100644 index 000000000..0e5c6b1b0 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/de/floater_prim_import.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater name="Import" title="Fortschritt des Imports"> + <text name="name_label"> Fortschritt </text> +</floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_report_abuse.xml b/linden/indra/newview/skins/default/xui/de/floater_report_abuse.xml index 6a7246d1e..048066e53 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_report_abuse.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_report_abuse.xml @@ -119,6 +119,7 @@ dann auf das Objekt: <combo_item name="Indecency__Broadly_offensive_content_or_conduct"> Unanständigkeit > Anstößige Inhalte oder Handlungen in der Öffentlichkeit </combo_item> +<!-- 58 = deprecated by AO --> <combo_item name="Indecency__Inappropriate_avatar_name"> Unanständigkeit > Anstößiger Avatarname </combo_item> @@ -138,7 +139,7 @@ dann auf das Objekt: Intoleranz </combo_item> <combo_item name="Land__Abuse_of_sandbox_resources"> - Land > Missbrauch der Sandbox-Ressourcen + Land > Missbrauch von Sandbox-Ressourcen </combo_item> <combo_item name="Land__Encroachment__Objects_textures"> Land > Unbefugte Nutzung > Objekte/Texturen @@ -160,7 +161,7 @@ dann auf das Objekt: Name des Beschuldigten: </text> <button label="Einwohner auswählen" label_selected="" name="select_abuser" tool_tip="Den Namen des Beschuldigten aus einer Liste wählen"/> - <check_box label="Name des Täters ist nicht bekannt" name="omit_abuser_name" tool_tip="Wählen Sie diese Option, wenn Ihnen der Name des Täters unbekannt ist"/> + <check_box label="Name des Täters unbekannt" name="omit_abuser_name" tool_tip="Wählen Sie diese Option, wenn Ihnen der Name des Täters nicht bekannt ist"/> <text name="abuser_name_title2"> Ort des Missbrauchs: </text> diff --git a/linden/indra/newview/skins/default/xui/de/floater_report_bug.xml b/linden/indra/newview/skins/default/xui/de/floater_report_bug.xml index 2c8734ef5..fdcde2040 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_report_bug.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_report_bug.xml @@ -1,5 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater name="bug_reporter" title="Fehler melden"> + <texture_picker label="" name="screenshot"/> + <check_box bottom_delta="-20" label="Screenshot einschließen" name="screen_check"/> <text name="reporter_title"> Melder: </text> @@ -24,13 +26,11 @@ dann auf das Objekt: <text name="owner_name_label"> Eigentümer: </text> - <check_box label="Screenshot einschließen" name="screen_check" /> - <texture_picker label="Arbeitet..." name="screenshot" /> <text name="owner_name"> Hendrerit Vulputate </text> <combo_box name="category_combo" - tool_tip="Category -- select the category that best describes this report"> + tool_tip="Kategorie -- wählen Sie die Kategorie aus, die am besten auf diesen Bericht zutrifft"> <combo_item name="Selectcategory"> Kategorie auswählen </combo_item> @@ -74,7 +74,7 @@ dann auf das Objekt: Skript </combo_item> <combo_item name="Sound"> - Sound + Klang </combo_item> <combo_item name="Stipends"> Stipendium diff --git a/linden/indra/newview/skins/default/xui/de/floater_rlv_behaviour.xml b/linden/indra/newview/skins/default/xui/de/floater_rlv_behaviour.xml new file mode 100644 index 000000000..a08d9b205 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/de/floater_rlv_behaviour.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater name="rlvBehaviours" + title="Active RLV-Beschränkungen"> + <scroll_list name="behaviour_list"> + <column label="Beschränkung" name="behaviour" /> + <column label="Objektname" name="name" /> + </scroll_list> +</floater> \ No newline at end of file diff --git a/linden/indra/newview/skins/default/xui/de/floater_telehub.xml b/linden/indra/newview/skins/default/xui/de/floater_telehub.xml index 264411c16..fef4fcd95 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_telehub.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_telehub.xml @@ -23,10 +23,10 @@ <text name="spawn_point_help"> Wählen Sie ein Objekt und klicken zur Positionsangabe auf „Hinzufügen“. Anschließend -können sie das Objekt verschieben oder löschen. +können Sie das Objekt verschieben oder löschen. Positionsangaben sind relativ zum Telehub-Mittelpunkt. -Wählen Sie ein Objekt aus, um seine Position in -der Welt anzuzeigen. +Wählen Sie ein Objekt der Liste aus, um seine +Position in der Welt anzuzeigen. </text> </floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_teleport_history.xml b/linden/indra/newview/skins/default/xui/de/floater_teleport_history.xml new file mode 100644 index 000000000..7980f1edb --- /dev/null +++ b/linden/indra/newview/skins/default/xui/de/floater_teleport_history.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater name="teleporthistory" title="Teleportier-Historie"> + <tab_container label="TP-Listenregister" name="tplisttabs"> + <panel label="Teleportiert nach" name="TP-in"> + <scroll_list name="places_list_in"> + <column label="Region" name="region" /> + <column label="Position" name="position" /> + <column label="Besucht" name="visited" /> + <!--Hidden fields, used as storage for prebuilt strings, please keep at width 0--> + <column label="SLURL" name="slurl" /> + <column label="Sim String" name="simstring" /> + </scroll_list> + </panel> + <panel label="Teleportiert von" name="TP-out"> + <scroll_list name="places_list_out"> + <column label="Region" name="region" /> + <column label="Position" name="position" /> + <column label="Besucht" name="visited" /> + <!--Hidden fields, used as storage for prebuilt strings, please keep at width 0--> + <column label="SLURL" name="slurl" /> + <column label="Sim String" name="simstring" /> + </scroll_list> + </panel> + </tab_container> + <button label="Teleportieren" label_selected="Teleportieren" + name="teleport" tool_tip="Teleportiert zum ausgewählten Ort" /> + <button label="Auf Karte zeigen" label_selected="Auf Karte zeigen" + name="show_on_map" + tool_tip="Zentriert die Karte auf diesen Ort" /> + <button label="Historie löschen" + name="clear_history" + tool_tip="Gesicherte Teleportier-Historie löschen" /> + <button label="SLURL auf Zwischenablage kopieren" name="copy_slurl" + tool_tip="Kopiert den aktuellen Ort als SLURL, um ihn im Internet zu nutzen." /> +</floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_texture_ctrl.xml b/linden/indra/newview/skins/default/xui/de/floater_texture_ctrl.xml index 4aa7db4d3..efa21fd26 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_texture_ctrl.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_texture_ctrl.xml @@ -9,16 +9,38 @@ <text type="string" length="1" name="unknown"> Maße: [DIMENSIONS] </text> + <button label="Standard" label_selected="Standard" name="Default" /> <button label="Keine" label_selected="Keine" name="None" /> <button label="Leer" label_selected="Leer" name="Blank" /> + <button label="Unsichtbar" label_selected="Unsichtbar" name="Invisible" /> <check_box label="Ordner anzeigen" name="show_folders_check" /> - <search_editor label="Suchanfrage hier eintippen" name="inventory search editor" /> <check_box label="Sofort übernehmen" name="apply_immediate_check" /> <button label="" label_selected="" name="Pipette" /> <button label="Abbrechen" label_selected="Abbrechen" name="Cancel" /> <button label="Auswählen" label_selected="Auswählen" name="Select" /> - <text name="pick title"> + <string name="pick title"> Auswählen: - </text> + </string> + + <tab_container name="actions_tab_container"> + <panel label="Inventar" name="server_tab"> + <search_editor label="Suchanfrage hier eintippen" name="inventory search editor" /> + <inventory_panel name="inventory panel" /> + </panel> + <panel label="Computer" name="local_tab"> + <!-- tag: vaa emerald local_asset_browser [begin] --> + <text name="select_local"> + Textur auf Ihrem Computer für Vorschau in-welt auswählen + </text> + <button label="Hinzufügen" name="Add" width="70" /> + <button label="Entfernen" name="Remove" /> + <button label="Eigenschaften..." name="Browser" /> + <scroll_list name="local_name_list" > + <column name="unit_name" label="Name" /> + <column name="unit_id_HIDDEN" label="ID" /> + </scroll_list> + <!-- tag: vaa emerald local_asset_browser [end] --> + </panel> + </tab_container> </floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_tools.xml b/linden/indra/newview/skins/default/xui/de/floater_tools.xml index 165d0a71c..aa8170b5c 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_tools.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_tools.xml @@ -1,21 +1,38 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="toolbox floater" title="" short_title="Bauen"> +<floater name="toolbox floater" title="" short_title="Bauen" width="282"> + +<!-- Main floater tabs --> + <button label="" label_selected="" name="button focus" tool_tip="Fokus"/> <button label="" label_selected="" name="button move" tool_tip="Verschieben"/> <button label="" label_selected="" name="button edit" tool_tip="Bearbeiten"/> <button label="" label_selected="" name="button create" tool_tip="Erstellen"/> <button label="" label_selected="" name="button land" tool_tip="Land"/> - <check_box label="Zoom" name="radio zoom"/> + +<!-- Focus panel --> + + <check_box label="Zoom:" name="radio zoom"/> <check_box label="Orbit (Strg)" name="radio orbit"/> <check_box label="Schwenken (Strg-Umschalt)" name="radio pan"/> + +<!-- Move panel --> + <check_box label="Verschieben" name="radio move"/> <check_box label="Heben (Strg)" name="radio lift"/> <check_box label="Rotieren (Strg-Umschalt)" name="radio spin"/> + +<!-- Edit panel --> + <check_box label="Position" name="radio position"/> <check_box label="Drehen (Strg)" name="radio rotate"/> <check_box label="Dehnen (Strg-Umschalt)" name="radio stretch"/> <check_box label="Textur auswählen" name="radio select face"/> <check_box label="Verknüpfte Teile bearbeiten" name="checkbox edit linked parts"/> + <button label="Verknüpfen" label_selected="Verknüpfen" + left="10" name="link_btn" width="68" /> + <button label="Trennen" label_selected="Trennen" + name="unlink_btn" width="68" /> + <text name="text ruler mode"> Lineal: </text> @@ -33,10 +50,16 @@ <check_box label="Beide Seiten dehnen" name="checkbox uniform"/> <check_box label="Texturen dehnen" name="checkbox stretch textures"/> <check_box label="Raster verwenden" name="checkbox snap to grid"/> - <button label="Optionen..." label_selected="Optionen..." name="Options..."/> + <button label="Bauoptionen..." label_selected="Bauoptionen..." name="Options..."/> + +<!-- Help text --> + <text name="text status"> Zum Verschieben ziehen, zum Kopieren Umschalttaste-Ziehen </text> + +<!-- Create panel --> + <button label="" label_selected="" name="ToolCube" tool_tip="Würfel"/> <button label="" label_selected="" name="ToolPrism" tool_tip="Prisma"/> <button label="" label_selected="" name="ToolPyramid" tool_tip="Pyramide"/> @@ -52,10 +75,15 @@ <button label="" label_selected="" name="ToolRing" tool_tip="Ring"/> <button label="" label_selected="" name="ToolTree" tool_tip="Baum"/> <button label="" label_selected="" name="ToolGrass" tool_tip="Gras"/> + <text name="tree_grass_label" /> + <combo_box name="trees_grass" /> <check_box label="Auswahl behalten" name="checkbox sticky"/> <check_box label="Auswahl kopieren" name="checkbox copy selection"/> <check_box label="Zentrieren" name="checkbox copy centers"/> <check_box label="Drehen" name="checkbox copy rotates"/> + +<!-- Land panel --> + <check_box label="Land auswählen" name="radio select land"/> <check_box label="Einebnen" name="radio flatten"/> <check_box label="Anheben" name="radio raise"/> @@ -68,10 +96,10 @@ Planierraupe: </text> <text name="Dozer Size:"> - Größe + Größe: </text> <text name="Strength:"> - Stärke + Stärke: </text> <text name="obj_count"> Ausgewählte Objekte: [COUNT] @@ -79,7 +107,13 @@ <text name="prim_count"> Primitive: [COUNT] </text> - <tab_container name="Object Info Tabs" tab_max_width="150" tab_min_width="30"> + <text name="link_num"> + Linknummer: [NUMBER] + </text> + +<!-- Sub-tabs --> + + <tab_container name="Object Info Tabs" tab_max_width="150" tab_min_width="30" width="280"> <panel label="Allgemein" name="General"> <text name="Name:"> Name: @@ -91,16 +125,20 @@ Ersteller: </text> <text name="Creator Name"> - Thrax Linden + Imprudent Linden </text> - <button label="Profil..." label_selected="Profil..." name="button creator profile"/> <text name="Owner:"> Eigentümer: </text> <text name="Owner Name"> - Thrax Linden - </text> - <button label="Profil..." label_selected="Profil..." name="button owner profile"/> + Imprudent Linden + </text> + <text name="Last Owner:"> + Last Owner: + </text> + <text name="Last Owner Name"> + Imprudent Linden + </text> <text name="Group:"> Gruppe: </text> @@ -116,33 +154,35 @@ </text> <check_box label="Mit Gruppe teilen" left="6" name="checkbox share with group" tool_tip="Allen Mitgliedern der zugeordneten Gruppe die Erlaubnis erteilen, Ihre Berechtigungen für dieses Objekt zu teilen und zu verwenden. Sie müssen Übereignen, um Rollenbeschränkungen zu aktivieren."/> <string name="text deed continued"> - Übertragung... + Übereignung... </string> <string name="text deed"> - Übertragung + Übereignung </string> - <button label="Übertragung..." label_selected="Übertragung..." name="button deed" tool_tip="In der Gruppe gemeinsam verwendete Objekte können von einem Gruppenfunktionär übertragen werden."/> - <text name="Anyone can:"> - Jeder: - </text> - <check_box label="Bewegen" name="checkbox allow everyone move"/> - <check_box label="Kopieren" name="checkbox allow everyone copy"/> + <button label="Übereignung..." label_selected="Übereignung..." name="button deed" tool_tip="In der Gruppe gemeinsam verwendete Objekte können von einem Gruppenoffizier übereignet werden."/> <check_box label="In Suche anzeigen" left="6" name="search_check" tool_tip="Dieses Objekt in Suchergebnissen anzeigen"/> - <check_box label="Zu verkaufen" left="6" name="checkbox for sale"/> + <check_box label="Zu verkaufen:" left="6" name="checkbox for sale"/> <text name="Cost"> - Preis:L$ + Preis: [CURRENCY] </text> <radio_group name="sale type"> <radio_item name="Original"> Original </radio_item> <radio_item name="Copy"> - Kopieren + Kopie </radio_item> <radio_item name="Contents"> Inhalt </radio_item> </radio_group> + <button label="Schlüssel kopieren" label_selected="Schlüsselkopie" name="button copy key" width="78" + tool_tip="Den/die Schlüssel eines Objekts in die Zwischenablage kopieren" /> + <text name="Anyone can:"> + Jeder: + </text> + <check_box label="Bewegen" name="checkbox allow everyone move"/> + <check_box label="Kopieren" name="checkbox allow everyone copy"/> <text name="Next owner can:"> Nächster Eigentümer kann: </text> @@ -152,6 +192,8 @@ <text name="label click action"> Bei Linksklicken: </text> + <!-- Do not reorder these items, the index numbers are + used internally. JC --> <combo_box name="clickaction" width="178"> <combo_item name="Touch/grab(default)"> Berühren/Greifen (Standard) @@ -209,13 +251,13 @@ Gesamtes Objekt muss gewählt werden, um Berechtigungen festzulegen. </string> <string name="Cost Default"> - Preis:L$ + Preis: [CURRENCY] </string> <string name="Cost Total"> - Summe:L$ + Summe: [CURRENCY] </string> <string name="Cost Per Unit"> - Stückpreis:L$ + Stückpreis: [CURRENCY] </string> <string name="Cost Mixed"> Mischpreis @@ -224,31 +266,43 @@ Mischverkauf </string> </panel> - <panel label="Objekt" name="Object"> + +<!-- Object sub-tab --> + + <panel label="Objekt" name="Object" width="272"> <text name="select_single"> - Wählen Sie nur ein Primitivum aus, um Parameter zu bearbeiten. + Nur einzelne Primitiva bearbeiten. </text> <text name="edit_object"> Objektparameter bearbeiten: </text> - <check_box label="Gesperrt" name="checkbox locked" tool_tip="Verhindert, dass Objekt verschoben oder gelöscht wird. Oft beim Bauen nützlich, um unbeabsichtigte Bearbeitungen zu vermeiden."/> - <check_box label="Physisch" name="Physical Checkbox Ctrl" tool_tip="Gestattet, das Objekt geschoben und von Schwerkraft beeinflusst wird"/> - <check_box label="Temporär" name="Temporary Checkbox Ctrl" tool_tip="Verursacht, dass Objekt 1 Minute nach Erstellung gelöscht wird."/> + <check_box label="Gesperrt" name="checkbox locked" tool_tip="Verhindert, dass das Objekt verschoben oder gelöscht wird. Oft beim Bauen nützlich, um unbeabsichtigte Bearbeitungen zu vermeiden."/> + <check_box label="Physisch" name="Physical Checkbox Ctrl" tool_tip="Gestattet, dass das Objekt geschoben und von Schwerkraft beeinflusst wird"/> + <check_box label="Temporär" name="Temporary Checkbox Ctrl" tool_tip="Verursacht, dass das Objekt 1 Minute nach Erstellung gelöscht wird."/> <check_box label="Phantom" name="Phantom Checkbox Ctrl" tool_tip="Verursacht, dass Objekt nicht mit anderen Objekten oder Avataren kollidiert"/> + <text name="label position"> - Position (Meter) + Position (Meter): </text> <spinner label="X" name="Pos X"/> <spinner label="Y" name="Pos Y"/> <spinner label="Z" name="Pos Z"/> + <button label="C" name="copypos" tool_tip="Position kopieren" /> + <button label="P" name="pastepos" tool_tip="Position einfügen" /> + <button label="p" name="pasteposclip" tool_tip="Position von Zwischenablage einfügen" /> + <text name="label size"> - Größe (Meter) + Größe (Meter): </text> <spinner label="X" name="Scale X"/> <spinner label="Y" name="Scale Y"/> <spinner label="Z" name="Scale Z"/> + <button label="C" name="copysize" tool_tip="Größe kopieren" /> + <button label="P" name="pastesize" tool_tip="Größe einfügen" /> + <button label="p" name="pastesizeclip" tool_tip="Größe von Zwischenablage einfügen" /> + <text name="label rotation"> - Rotation (Grad) + Rotation (Grad): </text> <spinner label="X" name="Rot X"/> <spinner label="Y" name="Rot Y"/> @@ -256,6 +310,14 @@ <text name="label material"> Material </text> + <button label="C" name="copyrot" +tool_tip="Rotation kopieren" /> + <button label="P" name="pasterot" tool_tip="Rotation einfügen" /> + <button label="p" name="pasterotclip" tool_tip="Rotation von Zwischenablage einfügen" /> + + <text name="label material"> + Material: + </text> <combo_box name="material"> <combo_item name="Stone"> Stein @@ -279,10 +341,11 @@ Gummi </combo_item> </combo_box> - <text left="115" name="label basetype"> + <button label="Bau-Mathe" label_selected="Bau-Mathe" tool_tip="mathem. Konstanten des Objekts" name="build_math_constants" /> + <text left="130" name="label basetype"> Bausteintyp </text> - <combo_box left="115" name="comboBaseType"> + <combo_box left="130" name="comboBaseType"> <combo_item name="Box"> Quader </combo_item> @@ -308,23 +371,23 @@ Geformt </combo_item> </combo_box> - <text left="115" name="text cut" width="146"> - Pfadschnitt Beginn und Ende + <text left="130" name="text cut" width="146"> + Pfadschnitt Beginn und Ende: </text> - <spinner label="B" left="115" name="cut begin"/> - <spinner label="E" left="115" name="cut end"/> - <text left="115" name="text hollow"> - Hohl + <spinner label="B" left="130" name="cut begin"/> + <spinner label="E" left="130" name="cut end"/> + <text left="130" name="text hollow"> + Hohl: </text> - <text left="115" name="text skew"> - Versatz + <text left="130" name="text skew"> + Versatz: </text> - <spinner left="115" name="Scale 1"/> - <spinner left="115" name="Skew"/> - <text left="115" name="Hollow Shape"> - Hohlform + <spinner left="130" name="Scale 1"/> + <spinner left="130" name="Skew"/> + <text left="130" name="Hollow Shape"> + Hohlform: </text> - <combo_box left="115" name="hole"> + <combo_box left="130" name="hole"> <combo_item name="Default"> Standard </combo_item> @@ -338,57 +401,59 @@ Dreieck </combo_item> </combo_box> - <text left="115" name="text twist"> - Torsion + <text left="130" name="text twist"> + Torsion Beginn und Ende: </text> - <spinner label="B" left="115" name="Twist Begin"/> - <spinner label="E" left="115" name="Twist End"/> - <text left="115" name="scale_taper"> - Verjüngung + <spinner label="B" left="130" name="Twist Begin"/> + <spinner label="E" left="130" name="Twist End"/> + <text left="130" name="scale_taper"> + Verjüngung: </text> - <text left="115" name="scale_hole"> - Lochgröße + <text left="130" name="scale_hole"> + Lochgröße: </text> - <spinner label="X" left="115" name="Taper Scale X"/> - <spinner label="Y" left="115" name="Taper Scale Y"/> - <text left="115" name="text topshear"> - Verscherung + <spinner label="X" left="130" name="Taper Scale X"/> + <spinner label="Y" left="130" name="Taper Scale Y"/> + <text left="130" name="text topshear"> + Verscherung: </text> - <spinner label="X" left="115" name="Shear X"/> - <spinner label="Y" left="115" name="Shear Y"/> - <text left="115" name="advanced_cut" width="153"> - Profilschnitt-Beginn und Ende + <spinner label="X" left="130" name="Shear X"/> + <spinner label="Y" left="130" name="Shear Y"/> + <text left="130" name="advanced_cut" width="153"> + Profilschnitt-Beginn und Ende: </text> - <text left="115" name="advanced_dimple"> - Vertiefung-Beginn und Ende + <text left="130" name="advanced_dimple"> + Vertiefung-Beginn und Ende: </text> - <text name="advanced_slice"> - Anfang/Ende abschneiden + <text left="130" name="advanced_slice"> + Anfang/Ende abschneiden: </text> - <spinner label="B" left="115" name="Path Limit Begin"/> + <spinner label="B" left="130" name="Path Limit Begin"/> <spinner label="E" name="Path Limit End"/> - <text left="115" name="text taper2"> - Verjüngung + <text left="130" name="text taper2"> + Verjüngung: </text> - <spinner label="X" left="115" name="Taper X"/> + <spinner label="X" left="130" name="Taper X"/> <spinner label="Y" name="Taper Y"/> - <text left="115" name="text radius delta"> - Radius + <text left="130" name="text radius delta"> + Radius: </text> <text name="text revolutions" width="74"> - Umdrehungen + Umdrehungen: </text> - <spinner left="115" name="Radius Offset"/> + <spinner left="130" name="Radius Offset"/> + <spinner name="Revolutions" /> + <texture_picker label="Textur für gestaltetes -Primitiv" name="sculpt texture control" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/> +Primitiv:" name="sculpt texture control" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/> <check_box bottom_delta="-34" label="Spiegeln" name="sculpt mirror control" tool_tip="Geformtes Primitiv entlang der X-Achse spiegeln."/> <check_box label="Wenden" name="sculpt invert control" tool_tip="Dreht die Normalen des geformten Primitivs von innen nach außen."/> <text name="label sculpt type"> - Naht + Naht: </text> <combo_box name="sculpt type control"> <combo_item name="None"> - (keiner) + (keine) </combo_item> <combo_item name="Sphere"> Kugel @@ -404,31 +469,38 @@ Primitiv" name="sculpt texture control" tool_tip="Klicken Sie hier, um ein Bild </combo_item> </combo_box> </panel> - <panel label="Eigenschaften" name="Features"> + +<!-- Features sub-tab --> + + <panel label="Eigenschaften" name="Features" height="25" > <text name="select_single"> - Wählen Sie nur einen einzelnen Baustein aus, um Eigenschaften zu bearbeiten. + Wählen Sie nur einen einzelnen Baustein aus, +um Eigenschaften zu bearbeiten. </text> - <text name="edit_object"> + <text name="edit_object" bottom_delta="-10" > Objekteigenschaften bearbeiten: </text> <check_box label="Flexibler Weg" name="Flexible1D Checkbox Ctrl" tool_tip="Gestattet, dass Objekt um die Z-Achse gebogen wird. (nur Client-Seite)"/> - <spinner label="Weichheit" name="FlexNumSections"/> - <spinner label="Schwerkraft" name="FlexGravity"/> - <spinner label="Ziehen" name="FlexFriction"/> - <spinner label="Wind" name="FlexWind"/> - <spinner label="Spannung" name="FlexTension"/> - <spinner label="Erzwingen X" name="FlexForceX"/> - <spinner label="Erzwingen Y" name="FlexForceY"/> - <spinner label="Erzwingen Z" name="FlexForceZ"/> - <check_box label="Licht" name="Light Checkbox Ctrl" tool_tip="Verursacht, dass Objekt Licht emittiert"/> + <spinner label="Weichheit:" name="FlexNumSections"/> + <spinner label="Schwerkraft:" name="FlexGravity"/> + <spinner label="Ziehen:" name="FlexFriction"/> + <spinner label="Wind:" name="FlexWind"/> + <spinner label="Spannung:" name="FlexTension"/> + <spinner label="Erzwingen X:" name="FlexForceX"/> + <spinner label="Erzwingen Y:" name="FlexForceY"/> + <spinner label="Erzwingen Z:" name="FlexForceZ"/> + <check_box label="Licht" name="Light Checkbox Ctrl" tool_tip="Verursacht, dass das Objekt Licht ausstrahlt"/> <text name="label color"> - Farbe + Farbe: </text> <color_swatch label="" name="colorswatch" tool_tip="Klicken, um Farbauswahl zu öffnen"/> - <spinner label="Intensität" name="Light Intensity"/> - <spinner label="Radius" name="Light Radius"/> - <spinner label="Abnehmend" name="Light Falloff"/> + <spinner label="Intensität:" name="Light Intensity"/> + <spinner label="Radius:" name="Light Radius"/> + <spinner label="Abnehmend:" name="Light Falloff"/> </panel> + +<!-- Texture sub-tab --> + <panel label="Textur" name="Texture"> <texture_picker label="Textur" name="texture control" tool_tip="Klicken, um ein Bild zu wählen"/> <color_swatch label="Farbe" name="colorswatch" tool_tip="Klicken, um Farbauswahl zu öffnen"/> @@ -520,12 +592,14 @@ Primitiv" name="sculpt texture control" tool_tip="Klicken Sie hier, um ein Bild Stuck </combo_item> <combo_item name="suction"> - Saugen + Sog </combo_item> <combo_item name="weave"> - gewoben + Gewebe </combo_item> </combo_box> + <check_box label="Ebene Texturen ausrichten" + name="checkbox planar align" tool_tip="Richtet Texturen auf allen ausgewählten Flächen nach der letzten Fläche aus. Benötigt ebene Texturzuordnung." /> <text name="tex scale"> Wiederholungen </text> @@ -556,32 +630,40 @@ Primitiv" name="sculpt texture control" tool_tip="Klicken Sie hier, um ein Bild (zuerst laden) </text> <button label="Ausrichten" label_selected="Ausrichten" name="button align"/> + <button label="Textur Mathe" label_selected="Textur Mathe" tool_tip="Texture math constants" name="texture_math_constants" /> </panel> <panel label="Inhalt" name="Contents"> <button label="Neues Skript" label_selected="Neues Skript..." name="button new script"/> <button label="Berechtigungen..." name="button permissions" width="118"/> + <panel name="ContentsInventory" /> </panel> </tab_container> + +<!-- Land Info sub-tab --> + <panel name="land info panel"> + <!-- Parcel Information --> <text name="label_parcel_info"> - Parzelleninformation + Parzelleninformation: </text> <text name="label_area_price"> - Preis: L$ [PRICE] für [AREA] m2. + Preis: [CURRENCY][PRICE] für [AREA] m2. </text> <text name="label_area"> Fläche: [AREA] m2 </text> - <button label="Info zu Land..." label_selected="Info zu Land..." name="button about land" width="110"/> + <button label="Landinfo..." label_selected="Landinfo..." name="button about land" width="110" /> <check_box label="Eigentümer anzeigen" name="checkbox show owners" tool_tip="Parzellen nach Eigentümer farbig kennzeichnen"/> <button label="?" label_selected="?" name="button show owners help" left_delta="130"/> + <!-- Modify Parcel --> <text name="label_parcel_modify"> - Parzelle ändern + Parzelle ändern: </text> <button label="Unterteilen..." label_selected="Unterteilen..." name="button subdivide land" width="110"/> <button label="Zusammenlegen" label_selected="Zusammenlegen" name="button join land" width="110"/> + <!-- Land Transactions --> <text name="label_parcel_trans"> - Land-Transaktionen + Land-Transaktionen: </text> <button label="Land kaufen..." label_selected="Land kaufen..." name="button buy land" width="110"/> <button label="Land aufgeben..." label_selected="Land aufgeben..." name="button abandon land" width="110"/> @@ -605,7 +687,7 @@ Primitiv" name="sculpt texture control" tool_tip="Klicken Sie hier, um ein Bild Ziehen, um Objekte zu verschieben, Strg zum Heben, Strg-Umschalt zum Drehen </string> <string name="status_place"> - Inworld klicken, um zu bauen. + In-Welt klicken, um zu bauen </string> <string name="status_selectland"> Klicken und ziehen, um Land auszuwählen diff --git a/linden/indra/newview/skins/default/xui/de/floater_top_objects.xml b/linden/indra/newview/skins/default/xui/de/floater_top_objects.xml index f9e7becee..8a196b1fd 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_top_objects.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_top_objects.xml @@ -41,7 +41,7 @@ Zeit </string> <string name="scripts_mono_time_label"> - Mono-Uhrzeit: + Mono-Uhrzeit </string> <string name="top_colliders_title"> Top-Kollisionsobjekte diff --git a/linden/indra/newview/skins/default/xui/de/floater_tos.xml b/linden/indra/newview/skins/default/xui/de/floater_tos.xml index 42f48fad4..b3fa2a4ed 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_tos.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_tos.xml @@ -2,18 +2,8 @@ <floater name="modal container" title=" "> <button label="Weiter" label_selected="Weiter" name="Continue" /> <button label="Abbrechen" label_selected="Abbrechen" name="Cancel" /> - <radio_group name="tos_agreement"> - <radio_item name="radio_disagree"> - Ich stimme den Nutzungsbedingungen nicht zu - </radio_item> - <radio_item name="radio_agree"> - Ich stimme den Nutzungsbedingungen zu - </radio_item> - </radio_group> - <text name="tos_title"> - Nutzungsvereinbarung - </text> - <check_box label="Ich stimme den Nutzungsbedingungen zu" name="agree_chk" /> + <check_box label="Ich stimme den Nutzungsbedingungen zu" + name="agree_chk" /> <text name="tos_heading"> Lesen Sie die folgenden Nutzungsbedingungen sorgfältig durch. Sie müssen dieser Vereinbarung zustimmen, um Second Life benutzen zu können. @@ -21,7 +11,8 @@ zustimmen, um Second Life benutzen zu können. <text_editor name="tos_text"> TOS_TEXT </text_editor> - <text name="real_url"> + + <string name="real_url"> http://secondlife.com/app/tos/ - </text> + </string> </floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_voice_license.xml b/linden/indra/newview/skins/default/xui/de/floater_voice_license.xml new file mode 100644 index 000000000..a79224b5b --- /dev/null +++ b/linden/indra/newview/skins/default/xui/de/floater_voice_license.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater name="modal container" title=""> + <button label="Weiter" label_selected="Weiter" name="Continue" /> + <button label="Abbrechen" label_selected="Abbrechen" name="Cancel" /> + <check_box label="Ich stimme den Bedingungen der Vivox-Richtlinie zur akzeptieren Nutzung zu" +name="agree_chk" /> + <text name="license_heading"> +Bitte lesen Sie das folgende Dokument sorgfältig durch. +Um Vivox Sprach-Chat nutzen zu können, müssen Sie den Bedingungen zustimmen. + </text> + <text_editor name="license_text"> + LICENSE_TEXT + </text_editor> + + <string name="real_url"> + http://www.vivox.com/vivox_aup.html + </string> +</floater> diff --git a/linden/indra/newview/skins/default/xui/de/floater_water.xml b/linden/indra/newview/skins/default/xui/de/floater_water.xml index 95b469434..b768a1285 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_water.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_water.xml @@ -4,7 +4,15 @@ Voreinstellungen: </text> <button label="Neu" label_selected="Neu" name="WaterNewPreset" /> - <button label="Speichern" label_selected="Speichern" name="WaterSavePreset" /> + <flyout_button label="Auf Platte speichern" + name="WaterSavePreset"> + <flyout_button_item name="save_inventory_item"> + In Inventar speichern + </flyout_button_item> + <flyout_button_item name="save_disk_item"> + Auf Platte speichern + </flyout_button_item> + </flyout_button> <button label="Löschen" label_selected="Löschen" name="WaterDeletePreset" /> <tab_container name="Water Tabs"> <panel label="Einstellungen" name="Settings"> @@ -12,7 +20,7 @@ Wassertrübungsfarbe </text> <button label=" ?" name="WaterFogColorHelp" left="175" /> - <color_swatch name="WaterFogColor" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen" /> + <color_swatch name="WaterFogColor" tool_tip="Hier klicken, um die Farbauswahl zu öffnen" /> <text name="WaterFogDensText"> Wassertrübungsdichte </text> diff --git a/linden/indra/newview/skins/default/xui/de/floater_wearable_save_as.xml b/linden/indra/newview/skins/default/xui/de/floater_wearable_save_as.xml index 89e351e49..5ca57e428 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_wearable_save_as.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_wearable_save_as.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater name="modal container" title=" "> +<floater name="modal container" title=""> <button label="Speichern" label_selected="Speichern" name="Save" /> <button label="Abbrechen" label_selected="Abbrechen" name="Cancel" /> <text type="string" length="1" name="Save item as:"> diff --git a/linden/indra/newview/skins/default/xui/de/floater_windlight_options.xml b/linden/indra/newview/skins/default/xui/de/floater_windlight_options.xml index 8df412dab..09ffcd291 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_windlight_options.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_windlight_options.xml @@ -4,10 +4,15 @@ Voreinstellungen: </text> <button label="Neu" label_selected="Neu" name="WLNewPreset" /> - <button label="Speichern" label_selected="Speichern" name="WLSavePreset" /> + <flyout_button label="Auf Platte speichern" name="WLSavePreset"> + <flyout_button_item name="save_inventory_item"> + In Inventar speichern + </flyout_button_item> + <flyout_button_item name="save_disk_item"> + Auf Platte speichern + </flyout_button_item> + </flyout_button> <button label="Löschen" label_selected="Löschen" name="WLDeletePreset" /> - <button label="Tageszyklus-Editor" label_selected="Tageszyklus-Editor" - name="WLDayCycleMenuButton" /> <tab_container name="WindLight Tabs"> <panel label="Atmosphäre" name="Atmosphere"> <text name="BHText"> @@ -184,6 +189,8 @@ <button label=" ?" name="WLClassicCloudsHelp" /> </panel> </tab_container> + <button label="Tageszyklus-Editor" label_selected="Tageszyklus-Editor" + name="WLDayCycleMenuButton" /> <string name="WLDefaultSkyNames"> A-12AM:A-12PM:A-3AM:A-3PM:A-4.30PM:A-6AM:A-6PM:A-9AM:A-9PM:Barcelona:Blizzard:Blue Midday:Coastal Afternoon:Coastal Sunset:Default:Desert Sunset:Fine Day:Fluffy Big Clouds:Foggy:Funky Funky:Funky Funky Funky:Gelatto:Ghost:Incongruent Truths:Midday 1:Midday 2:Midday 3:Midday 4:Night:Pirate:Purple:Sailor's Delight:Sheer Sensuality </string> diff --git a/linden/indra/newview/skins/default/xui/de/floater_world_map.xml b/linden/indra/newview/skins/default/xui/de/floater_world_map.xml index d28b55e8a..e0d95e6f6 100644 --- a/linden/indra/newview/skins/default/xui/de/floater_world_map.xml +++ b/linden/indra/newview/skins/default/xui/de/floater_world_map.xml @@ -14,19 +14,19 @@ Auktion </text> <text font="SansSerifSmall" name="land_for_sale_label"> - Land erhaeltlich + Land zum Verkauf </text> - <button label="Nach Hause" label_selected="Nach Hause" name="Go Home" tool_tip="Nach Hause teleportieren"/> + <button label="Nach Hause" label_selected="Nach Hause" name="Go Home" tool_tip="Zu Ihrem Zuhause teleportieren"/> <check_box label="Einwohner" name="people_chk"/> <check_box label="Infohub" name="infohub_chk"/> <check_box label="Telehub" name="telehubchk"/> - <check_box label="Land zu verkaufen" name="land_for_sale_chk"/> + <check_box label="Land zum Verkauf" name="land_for_sale_chk"/> <text name="events_label"> Events: </text> <check_box label="PG" name="event_chk"/> - <check_box label="Mature" name="event_mature_chk"/> - <check_box label="Adult" name="event_adult_chk"/> + <check_box label="Reif" name="event_mature_chk"/> + <check_box label="Erwachsen" name="event_adult_chk"/> <combo_box label="Online-Freunde" name="friend combo" tool_tip="Freund, der auf Karte angezeigt werden soll"> <combo_item name="none_selected"> Online-Freunde @@ -47,15 +47,15 @@ <column label="" name="sim_name"/> </scroll_list> <text name="location_label"> - Standort: + Ort: </text> - <spinner name="spin x" tool_tip="X-Koordinate der Position auf der Karte"/> - <spinner name="spin y" tool_tip="Y-Koordinate der Position auf der Karte"/> - <spinner name="spin z" tool_tip="Z-Koordinate der Position auf der Karte"/> - <button label="Teleportieren" label_selected="Teleportieren" name="Teleport" tool_tip="Zu ausgewählter Position teleportieren"/> - <button label="Gesuchte Position" label_selected="Ziel anzeigen" name="Show Destination" tool_tip="Karte auf ausgewählte Position zentrieren"/> + <spinner name="spin x" tool_tip="X-Koordinate des Ortes auf der Karte"/> + <spinner name="spin y" tool_tip="Y-Koordinate des Ortes auf der Karte"/> + <spinner name="spin z" tool_tip="Z-Koordinate des Ortes auf der Karte"/> + <button label="Teleportieren" label_selected="Teleportieren" name="Teleport" tool_tip="Zu ausgewähltem Ort teleportieren"/> + <button label="Ziel anzeigen" label_selected="Ziel anzeigen" name="Show Destination" tool_tip="Karte auf ausgewählten Ort zentrieren"/> <button label="Löschen" label_selected="Löschen" name="Clear" tool_tip="Verfolgung abschalten"/> - <button label="Meine Position" label_selected="Wo bin ich?" name="Show My Location" tool_tip="Karte auf Position Ihres Avatars zentrieren"/> - <button font="SansSerifSmall" label="SLURL in die Zwischenablage kopieren" name="copy_slurl" tool_tip="Kopiert die aktuelle Position als SLURL zur Verwendung im Web."/> + <button label="Meine Position" label_selected="Meine Position" name="Show My Location" tool_tip="Karte auf Position Ihres Avatars zentrieren"/> + <button font="SansSerifSmall" label="SLURL in Zwischenablage kopieren" name="copy_slurl" tool_tip="Kopiert die aktuelle Position als SLURL zur Verwendung im Internet."/> <slider label="Zoom" name="zoom slider"/> </floater> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_about_land.xml b/linden/indra/newview/skins/default/xui/en-us/floater_about_land.xml index 9bc91e742..c8aacbaa7 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_about_land.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_about_land.xml @@ -800,143 +800,633 @@ Only large parcels can be listed in search. No Pushing (Region Override) </string> </panel> - <panel border="true" bottom="-349" enabled="true" follows="left|top|right|bottom" - height="363" label="Media" left="1" mouse_opaque="true" - name="land_media_panel" width="458"> - <text type="string" length="1" bottom="-25" follows="left|top" font="SansSerifSmall" halign="left" height="16" - left="10" mouse_opaque="true" name="with media:" width="65"> - Media Type: - </text> - <combo_box allow_text_entry="false" bottom_delta="0" follows="left|top" height="18" - left="80" max_chars="20" name="media type" - tool_tip="Specify if the URL is a movie, web page, or other media" - width="120" /> - <text bottom_delta="0" follows="left|top" font="SansSerifSmall" height="16" - left_delta="130" name="mime_type" width="200" /> - <text type="string" length="1" bottom_delta="-20" follows="left|top" font="SansSerifSmall" halign="left" - height="16" left="10" name="at URL:" width="65"> - Media URL: - </text> - <line_editor bottom_delta="0" follows="left|top" font="SansSerifSmall" height="16" left="80" - max_length="255" name="media_url" right="-80" - select_all_on_focus_received="true" select_on_focus="true" - text_readonly_color="0.576471 0.662745 0.835294 1" /> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" halign="center" - height="16" label="Set..." label_selected="Set..." mouse_opaque="true" - name="set_media_url" right="-12" scale_image="true" width="60" /> - <text type="string" length="1" bottom_delta="-20" follows="left|top" font="SansSerifSmall" halign="left" - height="16" left="10" name="Description:" width="364"> + <panel + border="true" + border_visible="true" + bottom="-363" + enabled="true" + follows="left|top|right|bottom" + height="513" + label="Media" + left="1" + mouse_opaque="true" + name="land_media_panel" + width="458"> + <text + bottom="-25" + follows="left|top" + font="SansSerifSmall" + halign="left" + height="16" + left="10" + length="1" + mouse_opaque="true" + name="with media:" + type="string" + width="65"> + Type: + </text> + <combo_box + allow_text_entry="false" + bottom_delta="0" + follows="left|top" + height="18" + left="80" + max_chars="20" + name="media type" + tool_tip="Specify if the URL is a movie, web page, or other media" + width="120" /> + <text + bottom_delta="0" + follows="left|top" + font="SansSerifSmall" + height="16" + left_delta="130" + name="mime_type" + width="200" /> + <text type="string" + bottom_delta="-21" + follows="left|top" + font="SansSerifSmall" halign="left" + height="16" + left="10" + length="1" + name="at URL:" + width="65"> + Home URL: + </text> + <line_editor + bottom_delta="0" + follows="left|top|right" + font="SansSerifSmall" + height="16" + left="80" + max_length="255" + name="media_url" + right="-90" + select_all_on_focus_received="true" + select_on_focus="true" + text_readonly_color="0.576471 0.662745 0.835294 1" /> + <button + bottom_delta="0" + follows="right|top" + font="SansSerifSmall" + halign="center" + height="16" + label="Set..." + label_selected="Set..." + mouse_opaque="true" + name="set_media_url" + right="-12" + scale_image="true" + width="70" /> + <text + bottom_delta="-22" + follows="left|top" + font="SansSerifSmall" + halign="left" + height="16" + left="10" + length="1" + name="at URL:" + type="string" + width="65"> + Current URL: + </text> + <text + bottom_delta="0" + follows="left|top|right" + font="SansSerifSmall" + halign="left" + height="16" + left="80" + name="current_url" + right="-90" /> + <button + bottom_delta="0" + follows="right|top" + font="SansSerifSmall" + halign="center" + height="16" + label="Reset..." + label_selected="Reset..." + mouse_opaque="true" + name="reset_media_url" + right="-12" + scale_image="true" + width="70" /> + <check_box + bottom_delta="-22" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Hide URL" + left="80" + mouse_opaque="true" + name="hide_media_url" + radio_style="false" + tool_tip="Checking this option will hide the media URL from any non-authorized viewers of this parcel information. Note this is not available for HTML types." + width="150" /> + <text + bottom_delta="0" + follows="right|top" + font="SansSerifSmall" + halign="right" + height="16" + length="1" + name="media_reset" + right="-164" + tool_tip="Amount of time until parcel automatically reverts to default URL (0 for never return)" + type="string" + width="185"> + Return to Home URL in: + </text> + <spinner + bottom_delta="0" + decimal_digits="0" + enabled="false" + follows="right|top" + halign="right" + height="16" + increment="1" + initial_val="0" + max_val="1024" + min_val="0" + name="media_reset_time" + right="-90" + tool_tip="Amount of time until parcel reverts to default URL (0 for never return)" + width="64" /> + <text + bottom_delta="0" + follows="right|top" + font="SansSerifSmall" + halign="left" + height="16" + left_delta="70" + length="1" + name="minutes" + right="-10" + type="string"> + Minutes + </text> + <text + bottom_delta="-22" + follows="left|top" + font="SansSerifSmall" + halign="left" + height="16" + left="10" + length="1" + name="Description:" + type="string" + width="364"> Description: </text> - <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="0" - follows="left|top" font="SansSerifSmall" height="16" left="80" - max_length="255" name="url_description" right="-80" - select_all_on_focus_received="true" select_on_focus="true" - tool_tip="Text displayed next to play/load button" spell_check="true" /> - <text type="string" length="1" bottom_delta="-20" follows="left|top" font="SansSerifSmall" halign="left" - height="16" left="10" name="Media texture:" width="364"> - Replace -Texture: - </text> - <texture_picker allow_no_texture="true" bottom_delta="-64" can_apply_immediately="false" - default_image_name="Default" follows="left|top" height="80" label="" - left="80" name="media texture" tool_tip="Click to choose a picture" - width="64" /> - <text type="string" length="1" bottom_delta="48" follows="left|top" font="SansSerifSmall" halign="left" - height="16" left_delta="75" name="replace_texture_help" width="270"> - (Objects using this texture will show the movie or -web page after you click the play arrow.) - </text> - <text type="string" length="1" bottom_delta="-55" follows="left|top" font="SansSerifSmall" halign="left" - height="16" left="10" mouse_opaque="true" name="Options:" width="292"> - Media -Options: - </text> - <check_box bottom_delta="0" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" label="Auto scale" left="80" - mouse_opaque="true" name="media_auto_scale" radio_style="false" - tool_tip="Checking this option will scale the content for this parcel automatically. It may be slightly slower and lower quality visually but no other texture scaling or alignment will be required." - width="200" /> - <check_box bottom_delta="0" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" label="Loop Media" left="250" - mouse_opaque="true" name="media_loop" radio_style="false" - tool_tip="Play media in a loop. When the media has finished playing, it will restart from the beginning." - width="200" /> - <check_box bottom_delta="-20" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" label="Hide Media URL" left="80" - mouse_opaque="true" name="hide_media_url" radio_style="false" - tool_tip="Checking this option will hide the media url to any non-authorized viewers of this parcel information. Note this is not available for HTML types." - width="200" /> - <check_box bottom_delta="0" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" label="Hide Music URL" left="250" - mouse_opaque="true" name="hide_music_url" radio_style="false" - tool_tip="Checking this option will hide the music url to any non-authorized viewers of this parcel information" - width="200" /> - <text type="string" length="1" bottom_delta="-25" follows="left|top" font="SansSerifSmall" halign="left" - height="16" left="85" name="media_size" - tool_tip="Size to render Web media, leave 0 for default." width="85"> - Media size: - </text> - <spinner bottom_delta="0" decimal_digits="0" enabled="false" follows="left|top" - halign="right" height="16" increment="1" initial_val="0" left_delta="65" - max_val="1024" min_val="0" name="media_size_width" - tool_tip="Size to render Web media, leave 0 for default." width="64" /> - <spinner bottom_delta="0" decimal_digits="0" enabled="false" follows="left|top" - halign="right" height="16" increment="1" initial_val="0" left_delta="80" - max_val="1024" min_val="0" name="media_size_height" - tool_tip="Size to render Web media, leave 0 for default." width="64" /> - <text type="string" length="1" bottom_delta="0" follows="left|top" font="SansSerifSmall" halign="left" - height="16" left_delta="70" name="pixels" right="-10"> + <line_editor + bevel_style="in" + border_style="line" + border_thickness="1" + bottom_delta="0" + follows="left|top|right" + font="SansSerifSmall" + height="16" + left="80" + max_length="255" + name="url_description" + right="-90" + select_all_on_focus_received="true" + select_on_focus="true" + tool_tip="Text displayed next to play/load button" /> + <text + bottom_delta="-28" + follows="left|top" + font="SansSerifSmall" + halign="left" + height="16" + left="10" + length="1" + name="Media texture:" + type="string" + width="364"> + Texture: + </text> + <texture_picker + allow_no_texture="true" + bottom_delta="-64" + can_apply_immediately="false" + default_image_name="Default" + follows="left|top" + height="80" + label="" + left="80" + name="media texture" + tool_tip="Click to choose a texture" + width="64" /> + <text + type="string" + length="1" + bottom_delta="0" + follows="left|top" + font="SansSerifSmall" + halign="left" + height="80" + left_delta="75" + name="replace_texture_help" + width="270"> + Objects using this texture will show the movie or +web page after you click the play arrow. + +Select the thumbnail to choose a different texture. + </text> + <text + bottom_delta="-16" + follows="left|top" + font="SansSerifSmall" + halign="left" + height="16" + left="10" + length="1" + mouse_opaque="true" + name="Options:" + top_delta="0" + type="string" + width="64"> + Options: + </text> + <check_box + bottom_delta="0" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Loop" + left="80" + mouse_opaque="true" + name="media_loop" + radio_style="false" + tool_tip="Play media in a loop. When the media has finished playing, it will restart from the beginning." + width="200" /> + <check_box + bottom_delta="0" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Auto scale" + left_delta="80" + mouse_opaque="true" + name="media_auto_scale" + radio_style="false" + tool_tip="Checking this option will scale the content for this parcel automatically. It may be slightly slower and lower quality visually but no other texture scaling or alignment will be required." + width="200" /> + <text + bottom_delta="-24" + follows="left|top" + font="SansSerifSmall" + halign="left" + height="16" + left="10" + length="1" + name="media_size" + tool_tip="Size to render Web media, leave 0 for default." + type="string" + width="85"> + Media Size: + </text> + <spinner + bottom_delta="0" + decimal_digits="0" + enabled="false" + follows="left|top" + halign="right" + height="16" + increment="1" + initial_val="0" + left="80" + max_val="1024" + min_val="0" + name="media_size_width" + tool_tip="Width to render Web media, leave 0 for default." + width="60" /> + <spinner + bottom_delta="0" + decimal_digits="0" + enabled="false" + follows="left|top" + halign="right" + height="16" + increment="1" + initial_val="0" + left_delta="64" + max_val="1024" + min_val="0" + name="media_size_height" + tool_tip="Height to render Web media, leave 0 for default." + width="60" /> + <text + bottom_delta="0" + follows="left|top" + font="SansSerifSmall" + halign="left" + height="16" + left_delta="64" + length="1" + name="pixels" + type="string" + width="70"> pixels </text> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom_delta="-40" drop_shadow_visible="true" enabled="true" - follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" - height="16" left="10" mouse_opaque="true" name="MusicURL:" v_pad="0" - width="364"> + <text + bg_visible="false" + border_drop_shadow_visible="false" + border_visible="false" + bottom_delta="-30" + drop_shadow_visible="true" + enabled="true" + follows="left|top" + font="SansSerifSmall" + h_pad="0" + halign="left" + height="16" + left="10" + length="1" + mouse_opaque="true" + name="Interaction:" + type="string" + v_pad="0" + width="364"> + Interaction: + </text> + <radio_group + bottom_delta="-2" + draw_border="false" + enabled="true" + follows="left|top" + height="22" + left="80" + mouse_opaque="true" + name="radio_navigate_allow" + tab_stop="true" + width="219"> + <radio_item + bottom="-20" + enabled="true" + follows="left|top" + height="16" + left="0" + length="1" + mouse_opaque="true" + name="Anyone" + tool_tip="Any resident can interact with media." + type="string" + width="70"> + Anyone + </radio_item> + <radio_item + bottom="-20" + enabled="true" + follows="left|top" + height="16" + left="80" + length="1" + mouse_opaque="true" + name="Group" + tool_tip="Group permissions control who can interact with media." + type="string" + width="70"> + Group + </radio_item> + </radio_group> + <check_box + bottom_delta="-22" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Allow browsing only within these domains:" + left="80" + mouse_opaque="true" + name="check navigate filter" + radio_style="false" + width="292" /> + <line_editor + bevel_style="in" + border_style="line" + border_thickness="1" + bottom_delta="-20" + enabled="true" + follows="left|top|right" + font="SansSerifSmall" + handle_edit_keys_directly="false" + height="16" + left="80" + max_length="63" + mouse_opaque="true" + name="navigate_filter_domain" + right="-90" + select_all_on_focus_received="false" + select_on_focus="false" /> + <button + bottom_delta="0" + enabled="true" + follows="right|top" + font="SansSerifSmall" + halign="center" + height="16" + label="Add..." + label_selected="Add..." + right="-12" + mouse_opaque="true" + name="add_navigate_filter" + scale_image="true" + width="70" /> + <scroll_list + bottom_delta="-52" + can_resize="false" + column_padding="0" + draw_heading="false" + draw_stripes="false" + follows="left|top|right" + height="50" + halign="left" + left="80" + multi_select="false" + name="filter_list" + right="-90" + search_column="0" + sort_column="0"> + <column + halign="left" + label="Domain" + name="domain" + sort="domain"/> + </scroll_list> + <button + bottom_delta="0" + enabled="true" + follows="right|top" + font="SansSerifSmall" + halign="center" + height="16" + label="Remove" + label_selected="Remove" + right="-12" + mouse_opaque="true" + name="remove_navigate_filter" + scale_image="true" + width="70" /> + </panel> + <panel + border="true" + follows="left|top|right|bottom" + height="363" + label="Audio" + layout="topleft" + left_delta="0" + name="land_audio_panel" + top_delta="1" + width="458"> + <text + bottom="-45" + follows="left|top" + height="16" + layout="topleft" + left="10" + length="1" + name="MusicURL:" + type="string" + width="364"> Music URL: </text> - <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="0" - enabled="true" follows="left|top" font="SansSerifSmall" - handle_edit_keys_directly="false" height="16" left="80" max_length="255" - mouse_opaque="true" name="music_url" right="-15" - select_all_on_focus_received="true" select_on_focus="true"/> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom_delta="-40" drop_shadow_visible="true" enabled="true" - follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" - height="16" left="10" mouse_opaque="true" name="Sound:" v_pad="0" - width="364"> + <line_editor + border_style="line" + border_thickness="1" + bottom_delta="0" + follows="left|top|right" + height="16" + layout="topleft" + left="80" + max_length="255" + name="music_url" + right="-15" + select_on_focus="true" /> + <check_box + bottom_delta="-25" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Hide URL" + left="80" + mouse_opaque="true" + name="hide_music_url" + radio_style="false" + tool_tip="Checking this option will hide the music URL from any non-authorized viewers of this parcel information." + width="150" /> + <text + bottom_delta="-65" + follows="left|top" + height="16" + layout="topleft" + left="10" + length="1" + name="Sound:" + type="string" + width="364"> Sound: </text> - <check_box bottom_delta="0" enabled="true" follows="left|top" font="SansSerifSmall" - height="16" initial_value="false" - label="Restrict gesture and object sounds to this parcel" left="80" - mouse_opaque="true" name="check sound local" radio_style="false" - width="292" /> - <button bottom_delta="0" enabled="true" follows="left|top" font="SansSerif" - halign="center" height="18" label="?" label_selected="?" left="372" - mouse_opaque="true" name="?" width="18" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom_delta="-40" enabled="true" follows="left|top" font="SansSerifSmall" - h_pad="0" halign="left" height="16" left="10" mouse_opaque="false" - name="Voice settings:" tab_stop="false" v_pad="0" width="364"> + <check_box + bottom_delta="0" + follows="left|top" + height="16" + label="Restrict gesture and object sounds to this parcel" + layout="topleft" + left_delta="70" + name="check_sound_local" + width="200" /> + <button + bottom_delta="0" + follows="left|top" + height="18" + label="?" + label_selected="?" + layout="topleft" + left_delta="292" + name="?" + width="18" /> + <text + bottom_delta="-65" + follows="left|top" + height="16" + layout="topleft" + left="10" + length="1" + mouse_opaque="false" + name="Voice:" + type="string" + width="364"> Voice: </text> - <check_box bottom_delta="-0" enabled="true" follows="left|top" - height="54" left="80" mouse_opaque="true" name="parcel_enable_voice_channel" - tab_stop="true" width="463" - label="Enable Voice" - /> - <check_box bottom_delta="-0" enabled="false" follows="left|top" - height="54" left="80" mouse_opaque="true" name="parcel_enable_voice_channel_is_estate_disabled" - tab_stop="true" width="463" - label="Enable Voice (established by the Estate)" - /> - <check_box bottom_delta="-20" enabled="true" follows="left|top" - height="54" left="100" mouse_opaque="true" name="parcel_enable_voice_channel_parcel" - tab_stop="true" width="443" - label="Restrict Voice to this parcel" - /> + <radio_group + bottom_delta="-40" + draw_border="false" + enabled="true" + follows="left|top" + height="60" + left="80" + mouse_opaque="true" + name="parcel_voice_channel" + tab_stop="true" + width="219"> + <radio_item + bottom="-19" + enabled="true" + follows="left|top" + height="16" + left="0" + length="1" + mouse_opaque="true" + name="Estate" + tool_tip="Use the estate voice channel." + type="string" + width="70"> + Estate Channel + </radio_item> + <radio_item + bottom="-39" + enabled="true" + follows="left|top" + height="16" + left="0" + length="1" + mouse_opaque="true" + name="Parcel" + tool_tip="Restrict Voice to this parcel." + type="string" + width="70"> + Parcel Channel + </radio_item> + <radio_item + bottom="-59" + enabled="true" + follows="left|top" + height="16" + left="0" + length="1" + mouse_opaque="true" + name="Disabled" + tool_tip="Disable voice on this parcel." + type="string" + width="70"> + Disabled + </radio_item> + </radio_group> </panel> <panel border="true" bottom="-349" enabled="true" follows="left|top|right|bottom" height="333" label="Access" left="1" mouse_opaque="true" diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_avatar_picker.xml b/linden/indra/newview/skins/default/xui/en-us/floater_avatar_picker.xml index 0e5a64245..cd88c2ee3 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_avatar_picker.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_avatar_picker.xml @@ -58,7 +58,7 @@ font="SansSerif" mouse_opaque="true" name="Refresh" scale_image="TRUE" /> <slider bottom_delta="-20" left="10" follows="left|top" width="175" height="15" name="near_me_range" label="Range" control_name="NearMeRange" - min_val="5" max_val="40" increment="1" initial_val="20" decimal_digits="0" /> + min_val="5" max_val="512" increment="1" initial_val="20" decimal_digits="0" /> <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" bottom_delta="0" left="185" drop_shadow_visible="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="15" diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_command_line.xml b/linden/indra/newview/skins/default/xui/en-us/floater_command_line.xml index 35f47b5b5..13b334b2f 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_command_line.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_command_line.xml @@ -47,7 +47,7 @@ <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="-20" follows="left|top" font="SansSerifSmall" height="20" left_delta="0" max_length="256" mouse_opaque="true" tool_tip="" name="CmdLineChatbarCalc" control_name="CmdLineChatbarCalc" width="200"/> - <text bottom_delta="-20" follows="left|top" font="SansSerifSmall" height="16" left_delta="0" + <text bottom_delta="-20" follows="left|top" font="SansSerifSmall" height="16" left_delta="0" name="add_autokorrect" width="512">Add autocorrect word(cmd list|bad|good)</text> <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="-20" follows="left|top" font="SansSerifSmall" height="20" left_delta="0" max_length="256" mouse_opaque="true" @@ -105,4 +105,4 @@ <button bottom="-40" follows="left|top" font="SansSerifSmall" height="18" label="?" name="Help_CmdLine" tool_tip="Click here for help regarding the settings in this page." right="-10" width="18"/> -</floater> \ No newline at end of file +</floater> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_env_settings.xml b/linden/indra/newview/skins/default/xui/en-us/floater_env_settings.xml index e2bafbf81..0a4f2a9dd 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_env_settings.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_env_settings.xml @@ -58,9 +58,11 @@ <button bottom="-140" follows="left|top" font="SansSerifSmall" height="20" label="Use Estate Time" left="8" name="EnvUseEstateTimeButton" width="137" /> <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="20" - label="Advanced Sky" left="154" name="EnvAdvancedSkyButton" width="137" /> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="20" - label="Advanced Water" left="300" name="EnvAdvancedWaterButton" width="137" /> - <button bottom="-40" follows="left|top" font="SansSerif" height="18" label="?" + label="Advanced Sky" left="154" name="EnvAdvancedSkyButton" width="107" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="20" + label="Advanced Water" left="270" name="EnvAdvancedWaterButton" width="137" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="20" + label="Advanced WindLight Manager" left="416" name="EnvWLManager" width="177" /> + <button bottom="-40" follows="left|top" font="SansSerif" height="18" label="?" left="570" name="EnvSettingsHelpButton" width="22" /> </floater> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_media_browser.xml b/linden/indra/newview/skins/default/xui/en-us/floater_media_browser.xml index b30ca89d9..c1bfdcc8c 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_media_browser.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_media_browser.xml @@ -18,7 +18,20 @@ <button bottom_delta="0" enabled="true" follows="right|top" height="20" label="Home" left_delta="58" name="home" width="55" /> </layout_panel> - <layout_panel auto_resize="false" bottom="0" height="20" left="0" + <layout_panel auto_resize="false" bottom="0" height="20" left="0" name="time_controls" user_resize="false" + width="800"> + <button bottom="0" follows="left|top" height="20" label="rewind" left="0" name="rewind" + width="55" /> + <button bottom_delta="0" follows="left|top" height="20" label="" left_delta="55" + name="play" width="55" image_unselected="button_anim_play.tga" image_selected="button_anim_play_selected.tga" scale_image="true" /> + <button bottom_delta="0" follows="left|top" height="20" label="" left_delta="0" + name="pause" width="55" image_unselected="button_anim_pause.tga" image_selected="button_anim_pause_selected.tga" scale_image="true" /> + <button bottom_delta="0" follows="left|top" height="20" label="stop" + left_delta="65" name="stop" width="55" /> + <button bottom_delta="0" follows="left|top" height="20" label="forward" + left_delta="75" name="seek" width="55" /> + </layout_panel> + <layout_panel auto_resize="false" bottom="0" height="20" left="0" name="parcel_owner_controls" user_resize="false" width="540"> <button bottom="0" enabled="false" follows="left|top" height="20" label="Send Current URL to Parcel" left="0" name="assign" width="200" /> @@ -38,4 +51,10 @@ name="close" width="70" /> </layout_panel> </layout_stack> + <string name="home_page_url"> + http://www.secondlife.com + </string> + <string name="support_page_url"> + http://support.secondlife.com + </string> </floater> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_message_builder.xml b/linden/indra/newview/skins/default/xui/en-us/floater_message_builder.xml new file mode 100644 index 000000000..c7c49d839 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/floater_message_builder.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater name="Message Builder" title="Message Builder" width="400" min_width="400" height="600" min_height="600" can_close="true" can_resize="true" can_minimize="true"> + <scroll_list column_padding="0" draw_heading="false" follows="left|top|right" left="10" top="-25" + name="net_list" search_column="0" right="-10" bottom="450"> + <column dynamicwidth="true" name="text" label="text" /> + <column name="state" label="state" width="24" /> + </scroll_list> + <combo_box name="untrusted_message_combo" allow_text_entry="false" follows="left|top" left="10" top="-150" right="-370" bottom="433" tool_tip="No trust"> + </combo_box> + <combo_box name="trusted_message_combo" allow_text_entry="false" follows="left|top" left="30" top="-150" right="-350" bottom="433" tool_tip="Trust"> + </combo_box> + <text_editor name="message_edit" follows="left|top|right|bottom" left="10" top="-168" bottom="30" right="-10" max_length="65535"> + </text_editor> + <button name="send_btn" follows="right|bottom" left="310" top="-570" right="-10" bottom="10" label="Send" tool_tip="Send (Ctrl+Enter)"/> +</floater> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_message_log.xml b/linden/indra/newview/skins/default/xui/en-us/floater_message_log.xml new file mode 100644 index 000000000..e1ebfe2f1 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/floater_message_log.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater name="Message Log" title="Message Log" width="400" min_width="400" height="600" min_height="600" can_close="true" can_resize="true" can_minimize="true"> + <scroll_list column_padding="0" draw_heading="false" follows="left|top|right" left="10" top="-25" + name="net_list" search_column="0" right="-10" bottom="450"> + <column dynamicwidth="true" name="text" label="text" /> + <column name="icon0" label="icon0" width="24" /> + <column name="icon1" label="icon1" width="24" /> + </scroll_list> + <button name="filter_choice_btn" follows="left|top" left="10" top="-150" right="-370" bottom="430" label="…"/> + <line_editor name="filter_edit" follows="left|top|right" left="30" top="-149" right="-28" bottom="430" max_length="65535"/> + <button name="filter_apply_btn" follows="top|right" left="370" top="-150" right="-9" bottom="430" label="✔"/> + <button name="clear_log_btn" follows="top|right" left="370" top="-170" right="-9" bottom="410" label="C"/> + <scroll_list column_padding="0" draw_heading="false" follows="left|top|right" left="10" top="-190" + name="message_log" search_column="0" right="-10" bottom="200"> + <column name="sequence" label="sequence" width="48"/> + <column name="type" label="type" width="32"/> + <column name="direction" label="direction" width="32"/> + <column name="net" label="net" width="100"/> + <column name="name" label="name" width="128"/> + <!--<column name="flag_zer" label="zer" width="8"/> + <column name="flag_rel" label="rel" width="8"/> + <column name="flag_rsd" label="rsd" width="8"/> + <column name="flag_ack" label="ack" width="8"/>--> + <column name="summary" label="summary" dynamicwidth="true"/> + </scroll_list> + <text name="log_status_text" follows="left|top|right" left="10" top="-172" right="-10" height="20"> + </text> + <text_editor name="net_info" follows="left|top|right|bottom" left="10" top="-400" bottom="30" right="-10" enabled="false" max_length="65535"> + </text_editor> + <button name="send_to_message_builder_btn" follows="right|bottom" left="210" top="-570" right="-10" bottom="10" label="Send to Message Builder" enabled="false"/> +</floater> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_preferences.xml b/linden/indra/newview/skins/default/xui/en-us/floater_preferences.xml index 5b42e9ff3..939a8773f 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_preferences.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_preferences.xml @@ -16,9 +16,9 @@ width="90" /> <button bottom="-505" enabled="true" follows="left|bottom" font="SansSerif" halign="center" height="20" - help_url="http://secondlife.com/app/help/technical/preferences.php" - label="Help" label_selected="Help" left="9" mouse_opaque="true" - name="Help" scale_image="true" width="90" /> + help_url="http://support.imprudenceviewer.org/" + label="Support" left="9" mouse_opaque="true" + name="Support" scale_image="true" width="100" /> <tab_container bottom="-476" enabled="true" follows="left|top|right|bottom" height="455" left="0" mouse_opaque="false" name="pref core" tab_group="1" tab_position="left" tab_width="120" width="620" /> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_script_ed_panel.xml b/linden/indra/newview/skins/default/xui/en-us/floater_script_ed_panel.xml index 82a65b8c6..0175508c1 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_script_ed_panel.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_script_ed_panel.xml @@ -5,7 +5,7 @@ embedded_items="false" enabled="true" follows="left|top|right|bottom" font="Monospace" height="376" ignore_tab="false" left="4" max_length="65536" mouse_opaque="true" name="Script Editor" width="492" border_drop_shadow_visible="false" border_visible="false" bevel_style="none" border_style="line" border_thickness="0" - word_wrap="true" show_line_numbers="true"> + word_wrap="true" show_line_numbers="true" spell_check="false"> Loading... </text_editor> <button bottom="-499" enabled="true" follows="right|bottom" font="SansSerif" diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_snapshot.xml b/linden/indra/newview/skins/default/xui/en-us/floater_snapshot.xml index db4d1e12f..3b039de03 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_snapshot.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_snapshot.xml @@ -136,10 +136,10 @@ </combo_box> <spinner bottom_delta="-25" decimal_digits="0" follows="left|top" height="20" - increment="32" label="Width" label_width="30" left="10" max_val="4096" + increment="32" label="Width" label_width="30" left="10" max_val="6016" min_val="32" name="snapshot_width" width="95" allow_text_entry="false"/> <spinner bottom_delta="0" decimal_digits="0" follows="left|top" height="20" - increment="32" label="Height" label_width="35" left="110" max_val="4096" + increment="32" label="Height" label_width="35" left="110" max_val="6016" min_val="32" name="snapshot_height" width="95" allow_text_entry="false"/> <check_box bottom_delta="-20" follows="left|top" label="Constrain Proportions" left="10" name="keep_aspect_check" /> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml b/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml index 3e0a5fa58..c665563aa 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater bottom="-374" can_close="true" can_drag_on_left="false" can_minimize="true" - can_resize="false" follows="left|top" height="565" + can_resize="false" follows="left|top" height="575" left="308" min_height="100" min_width="100" mouse_opaque="true" name="toolbox floater" rect_control="ToolboxRect" sound_flags="0" title="" short_title="Build" width="272"> @@ -79,6 +79,10 @@ <check_box bottom_delta="-15" follows="left|top" font="SansSerifSmall" height="16" initial_value="false" label="Select faces to texture" left="4" mouse_opaque="true" name="radio select face" radio_style="true" width="114" /> + <check_box bottom_delta="-15" follows="left|top" font="SansSerifSmall" height="16" + initial_value="false" label="Align (Shift to Pack)" left="4" mouse_opaque="true" + name="radio align" radio_style="true" width="114" + tool_tip="Align aligns all selected prims' edges along an axis, Pack moves all selected prims' edges so they're touching" /> <check_box bottom_delta="-19" control_name="EditLinkedParts" follows="left|top" font="SansSerifSmall" height="16" initial_value="false" label="Edit linked parts" left="4" mouse_opaque="true" @@ -330,7 +334,7 @@ <!-- Sub-tabs --> - <tab_container bottom="-565" follows="left|top" height="384" left="0" mouse_opaque="false" + <tab_container bottom="-575" follows="left|top" height="384" left="0" mouse_opaque="false" name="Object Info Tabs" tab_max_width="52" tab_min_width="40" tab_position="top" width="272"> <panel border="true" bottom="-383" follows="left|top|right|bottom" height="367" @@ -1359,6 +1363,9 @@ <string name="status_move"> Drag to Move, Shift-Drag to Copy </string> + <string name="status_align"> + CTRL-A to align on an axis, CTRL-Shift-A to Pack + </string> <string name="status_modifyland"> Click and Hold to Modify Land </string> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_tos.xml b/linden/indra/newview/skins/default/xui/en-us/floater_tos.xml index 485cfcc27..beea02fa9 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_tos.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_tos.xml @@ -15,15 +15,14 @@ bottom="-50" drop_shadow_visible="true" follows="left|top" font="SansSerif" h_pad="0" halign="left" height="30" left="16" mouse_opaque="true" name="tos_heading" v_pad="0" width="552"> - Please read the following Terms of Service carefully. To continue logging in to Second Life, -you must accept the agreement. + Please read the following Terms of Service carefully. To continue logging in you must accept the agreement. </text> - <text_editor bottom="-376" embedded_items="false" follows="left|top" font="SansSerif" + <text_editor bottom="-376" embedded_items="false" follows="left|top" font="SansSerif" height="283" left="16" max_length="65536" mouse_opaque="true" name="tos_text" width="568" word_wrap="true"> - TOS_TEXT - </text_editor> + TOS_TEXT + </text_editor> <!-- Loading text says: "Loading Terms of Service..." URL encoded --> <web_browser bottom="-406" embedded_items="false" follows="left|top" font="SansSerif" height="340" left="16" max_length="65536" mouse_opaque="true" diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_water.xml b/linden/indra/newview/skins/default/xui/en-us/floater_water.xml index 441ce7b85..a05deb6f1 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_water.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_water.xml @@ -1,273 +1,276 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater bottom="-150" can_close="true" can_drag_on_left="false" can_minimize="true" - can_resize="false" height="240" left="50" min_height="200" - min_width="400" mouse_opaque="true" name="Water Floater" - rect_control="FloaterAdvancedWaterRect" title="Advanced Water Editor" - width="700"> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-50" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="10" mouse_opaque="true" name="KeyFramePresetsText" v_pad="0" - width="110"> - Water Presets: - </text> - <combo_box allow_text_entry="false" bottom="-52" follows="left|top" height="18" - left_delta="120" max_chars="20" mouse_opaque="true" - name="WaterPresetsCombo" width="150" /> - <button bottom="-53" enabled="true" font="SansSerif" halign="center" height="20" - label="" label_selected="" left_delta="-25" image_overlay="arrow_left.tga" - mouse_opaque="true" name="prev" scale_image="true" width="20" /> - <button bottom="-53" enabled="true" font="SansSerif" halign="center" height="20" - label="" label_selected="" left_delta="180" image_overlay="arrow_right.tga" - mouse_opaque="true" name="next" scale_image="true" width="20" /> - <button bottom="-53" enabled="true" font="SansSerif" halign="center" height="20" - label="New" right="-270" - mouse_opaque="true" name="WaterNewPreset" scale_image="true" width="100" /> - <flyout_button bottom_delta="0" follows="left|top" height="20" label="Save to Disk" - right="-140" halign="center" list_position="above" enabled="true" - mouse_opaque="true" width="125" name="WaterSavePreset"> - <flyout_button_item value="save_inventory_item" name="save_inventory_item"> - Save to Inventory - </flyout_button_item> - <flyout_button_item value="save_disk_item" name="save_disk_item"> - Save to Disk - </flyout_button_item> - </flyout_button> - <button bottom_delta="0" enabled="true" font="SansSerif" halign="center" height="20" - label="Delete File" label_selected="Delete File" right="-10" - mouse_opaque="true" name="WaterDeletePreset" scale_image="true" width="125" /> - <tab_container bottom="-240" follows="left|top" height="180" left="0" - mouse_opaque="false" name="Water Tabs" tab_position="top" width="700"> - <panel border="true" bottom="-240" follows="left|top|right|bottom" height="180" - label="Settings" left="1" mouse_opaque="false" - name="Settings" width="698"> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-20" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="10" mouse_opaque="true" name="BHText" v_pad="0" width="355"> - Water Fog Color - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="160" name="WaterFogColorHelp" width="18" /> - <color_swatch border_color="0.45098, 0.517647, 0.607843, 1" bottom="-80" - can_apply_immediately="true" color="0.5, 0.5, 0.5, 1" follows="left|top" - height="50" label="" left="40" mouse_opaque="true" - name="WaterFogColor" tool_tip="Click to open Color Picker" width="40" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-90" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="10" mouse_opaque="true" name="WaterFogDensText" v_pad="0" width="355"> - Fog Density Exponent - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="160" name="WaterFogDensityHelp" width="18" /> - <slider bottom_delta="-30" can_edit_text="false" control_name="WaterFogDensity" - decimal_digits="1" follows="left" height="10" increment=".1" - initial_val="16" label="" left="24" max_val="10" min_val="0" - mouse_opaque="true" name="WaterFogDensity" show_text="true" value="1.0" - width="200" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-130" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="10" mouse_opaque="true" name="WaterUnderWaterFogModText" v_pad="0" - width="355"> - Underwater Fog Modifier - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="160" name="WaterUnderWaterFogModHelp" width="18" /> - <slider bottom_delta="-30" can_edit_text="false" control_name="" decimal_digits="2" - follows="left" height="10" increment=".01" initial_val="16" label="" - left="24" max_val="2" min_val="0" mouse_opaque="true" - name="WaterUnderWaterFogMod" show_text="true" value="0.25" width="200" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-20" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="245" mouse_opaque="true" name="BDensText" v_pad="0" width="355"> - Reflection Wavelet Scale - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="395" name="WaterNormalScaleHelp" width="18" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-37" drop_shadow_visible="true" follows="left|top|right" - font="SansSerifSmall" h_pad="0" halign="center" height="16" - left="245" mouse_opaque="true" name="BHText2" v_pad="0" width="10"> - 1 - </text> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom_delta="-11" drop_shadow_visible="true" follows="left|top|right" - font="SansSerifSmall" h_pad="0" halign="center" height="16" - left_delta="0" mouse_opaque="true" name="BHText3" v_pad="0" width="10"> - 2 - </text> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom_delta="-11" drop_shadow_visible="true" follows="left|top|right" - font="SansSerifSmall" h_pad="0" halign="center" height="16" - left_delta="0" mouse_opaque="true" name="BHText4" v_pad="0" width="10"> - 3 - </text> - <slider bottom="-50" can_edit_text="false" control_name="WaterNormalScaleX" - decimal_digits="1" follows="left" height="10" increment="0.1" - initial_val="0.7" label="" left="259" max_val="10" min_val="0" - mouse_opaque="true" name="WaterNormalScaleX" show_text="true" value="1.0" - width="200" /> - <slider bottom_delta="-11" can_edit_text="false" control_name="WaterNormalScaleY" - decimal_digits="1" follows="left" height="10" increment="0.1" - initial_val="0.7" label="" left="259" max_val="10" min_val="0" - mouse_opaque="true" name="WaterNormalScaleY" show_text="true" value="1.0" - width="200" /> - <slider bottom_delta="-11" can_edit_text="false" control_name="WaterNormalScaleZ" - decimal_digits="1" follows="left" height="10" increment="0.1" - initial_val="0.7" label="" left="259" max_val="10" min_val="0" - mouse_opaque="true" name="WaterNormalScaleZ" show_text="true" value="1.0" - width="200" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-80" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="245" mouse_opaque="true" name="HDText" v_pad="0" width="355"> - Fresnel Scale - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="395" name="WaterFresnelScaleHelp" width="18" /> - <slider bottom_delta="-30" can_edit_text="false" control_name="WaterFresnelScale" - decimal_digits="2" follows="left" height="10" increment="0.01" - initial_val="0.7" label="" left="259" max_val="1" min_val="0" - mouse_opaque="true" name="WaterFresnelScale" show_text="true" value="1.0" - width="200" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-115" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="245" mouse_opaque="true" name="FresnelOffsetText" v_pad="0" - width="355"> - Fresnel Offset - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="395" name="WaterFresnelOffsetHelp" width="18" /> - <slider bottom_delta="-30" can_edit_text="false" control_name="WaterFresnelOffset" - decimal_digits="2" follows="left" height="10" increment="0.01" - initial_val="0.7" label="" left="259" max_val="1" min_val="0" - mouse_opaque="true" name="WaterFresnelOffset" show_text="true" value="1.0" - width="200" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-20" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="480" mouse_opaque="true" name="DensMultText" v_pad="0" width="355"> - Refract Scale Above - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="630" name="WaterScaleAboveHelp" width="18" /> - <slider bottom_delta="-30" can_edit_text="false" control_name="WaterScaleAbove" - decimal_digits="2" follows="left" height="10" increment="0.01" - initial_val="0.1" label="" left="494" max_val="1" min_val="0" - mouse_opaque="true" name="WaterScaleAbove" show_text="true" value="1.0" - width="200" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-53" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="480" mouse_opaque="true" name="WaterScaleBelowText" v_pad="0" - width="355"> - Refract Scale Below - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="630" name="WaterScaleBelowHelp" width="18" /> - <slider bottom_delta="-30" can_edit_text="false" control_name="WaterScaleBelow" - decimal_digits="2" follows="left" height="10" increment="0.01" - initial_val="0" label="" left="494" max_val="1" min_val="0" - mouse_opaque="true" name="WaterScaleBelow" show_text="true" value="0.0" - width="200" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-87" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="480" mouse_opaque="true" name="MaxAltText" v_pad="0" width="355"> - Blur Multiplier - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="630" name="WaterBlurMultiplierHelp" width="18" /> - <slider bottom_delta="-30" can_edit_text="false" control_name="WaterBlurMult" - decimal_digits="3" follows="left" height="10" increment=".001" - initial_val="0" label="" left="494" max_val=".16" min_val="0" - mouse_opaque="true" name="WaterBlurMult" show_text="true" value="0" - width="200" /> - </panel> - <panel border="true" bottom="-240" follows="left|top|right|bottom" height="180" - label="Image" left="1" mouse_opaque="false" name="Waves" - width="698"> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-20" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="10" mouse_opaque="true" name="BHText" v_pad="0" width="355"> - Big Wave Direction - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="155" name="WaterWave1Help" width="18" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-37" drop_shadow_visible="true" follows="left|top|right" - font="SansSerifSmall" h_pad="0" halign="center" height="16" - left="10" mouse_opaque="true" name="WaterWave1DirXText" v_pad="0" - width="10"> - X - </text> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom_delta="-11" drop_shadow_visible="true" follows="left|top|right" - font="SansSerifSmall" h_pad="0" halign="center" height="16" - left_delta="0" mouse_opaque="true" name="WaterWave1DirYText" v_pad="0" - width="10"> - Y - </text> - <slider bottom="-50" can_edit_text="false" control_name="WaterWave1DirX" - decimal_digits="2" follows="left" height="10" increment="0.01" - initial_val="0.7" label="" left="24" max_val="4" min_val="-4" - mouse_opaque="true" name="WaterWave1DirX" show_text="true" value="0.7" - width="200" /> - <slider bottom_delta="-11" can_edit_text="false" control_name="WaterWave1DirY" - decimal_digits="2" follows="left" height="10" increment="0.01" - initial_val="0.7" label="" left="24" max_val="4" min_val="-4" - mouse_opaque="true" name="WaterWave1DirY" show_text="true" value="0.7" - width="200" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-70" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="10" mouse_opaque="true" name="BHText2" v_pad="0" width="355"> - Little Wave Direction - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="155" name="WaterWave2Help" width="18" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-87" drop_shadow_visible="true" follows="left|top|right" - font="SansSerifSmall" h_pad="0" halign="center" height="16" - left="10" mouse_opaque="true" name="WaterWave2DirXText" v_pad="0" - width="10"> - X - </text> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom_delta="-11" drop_shadow_visible="true" follows="left|top|right" - font="SansSerifSmall" h_pad="0" halign="center" height="16" - left_delta="0" mouse_opaque="true" name="WaterWave2DirYText" v_pad="0" - width="10"> - Y - </text> - <slider bottom="-100" can_edit_text="false" control_name="WaterWave2DirX" - decimal_digits="2" follows="left" height="10" increment="0.01" - initial_val="0.7" label="" left="24" max_val="4" min_val="-4" - mouse_opaque="true" name="WaterWave2DirX" show_text="true" value="0.7" - width="200" /> - <slider bottom_delta="-11" can_edit_text="false" control_name="WaterWave2DirY" - decimal_digits="2" follows="left" height="10" increment="0.01" - initial_val="0.7" label="" left="24" max_val="4" min_val="-4" - mouse_opaque="true" name="WaterWave2DirY" show_text="true" value="0.7" - width="200" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-20" drop_shadow_visible="true" follows="left|top|right" - font="SansSerif" h_pad="0" halign="left" height="16" - left="240" mouse_opaque="true" name="BHText3" v_pad="0" width="355"> - Normal Map - </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" - left="365" name="WaterNormalMapHelp" width="18" /> - <texture_picker bottom="-165" height="143" label="" left="250" name="WaterNormalMap" - width="128" /> - </panel> - </tab_container> - <string name="WLDefaultWaterNames"> - Default:Glassy:Pond:Murky:Second Plague:SNAKE!!!:Valdez - </string> -</floater> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater bottom="-150" can_close="true" can_drag_on_left="false" can_minimize="true" + can_resize="false" height="240" left="50" min_height="200" + min_width="400" mouse_opaque="true" name="Water Floater" + rect_control="FloaterAdvancedWaterRect" title="Advanced Water Editor" + width="700"> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-50" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="10" mouse_opaque="true" name="KeyFramePresetsText" v_pad="0" + width="110"> + Water Presets: + </text> + <combo_box allow_text_entry="false" bottom="-52" follows="left|top" height="18" + left_delta="120" max_chars="20" mouse_opaque="true" + name="WaterPresetsCombo" width="150" /> + <button bottom="-53" enabled="true" font="SansSerif" halign="center" height="20" + label="" label_selected="" left_delta="-25" image_overlay="arrow_left.tga" + mouse_opaque="true" name="prev" scale_image="true" width="20" /> + <button bottom="-53" enabled="true" font="SansSerif" halign="center" height="20" + label="" label_selected="" left_delta="180" image_overlay="arrow_right.tga" + mouse_opaque="true" name="next" scale_image="true" width="20" /> + <button bottom="-53" enabled="true" font="SansSerif" halign="center" height="20" + label="New" right="-270" + mouse_opaque="true" name="WaterNewPreset" scale_image="true" width="100" /> + <flyout_button bottom_delta="0" follows="left|top" height="20" label="Save to Disk" + right="-140" halign="center" list_position="above" enabled="true" + mouse_opaque="true" width="125" name="WaterSavePreset"> + <flyout_button_item value="save_inventory_item" name="save_inventory_item"> + Save to Inventory + </flyout_button_item> + <flyout_button_item value="save_disk_item" name="save_disk_item"> + Save to Disk + </flyout_button_item> + <flyout_button_item value="send_to_server_item" name="send_to_server_item"> + Send to Server + </flyout_button_item> + </flyout_button> + <button bottom_delta="0" enabled="true" font="SansSerif" halign="center" height="20" + label="Delete File" label_selected="Delete File" right="-10" + mouse_opaque="true" name="WaterDeletePreset" scale_image="true" width="125" /> + <tab_container bottom="-240" follows="left|top" height="180" left="0" + mouse_opaque="false" name="Water Tabs" tab_position="top" width="700"> + <panel border="true" bottom="-240" follows="left|top|right|bottom" height="180" + label="Settings" left="1" mouse_opaque="false" + name="Settings" width="698"> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-20" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="10" mouse_opaque="true" name="BHText" v_pad="0" width="355"> + Water Fog Color + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="160" name="WaterFogColorHelp" width="18" /> + <color_swatch border_color="0.45098, 0.517647, 0.607843, 1" bottom="-80" + can_apply_immediately="true" color="0.5, 0.5, 0.5, 1" follows="left|top" + height="50" label="" left="40" mouse_opaque="true" + name="WaterFogColor" tool_tip="Click to open Color Picker" width="40" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-90" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="10" mouse_opaque="true" name="WaterFogDensText" v_pad="0" width="355"> + Fog Density Exponent + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="160" name="WaterFogDensityHelp" width="18" /> + <slider bottom_delta="-30" can_edit_text="false" control_name="WaterFogDensity" + decimal_digits="1" follows="left" height="10" increment=".1" + initial_val="16" label="" left="24" max_val="10" min_val="0" + mouse_opaque="true" name="WaterFogDensity" show_text="true" value="1.0" + width="200" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-130" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="10" mouse_opaque="true" name="WaterUnderWaterFogModText" v_pad="0" + width="355"> + Underwater Fog Modifier + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="160" name="WaterUnderWaterFogModHelp" width="18" /> + <slider bottom_delta="-30" can_edit_text="false" control_name="" decimal_digits="2" + follows="left" height="10" increment=".01" initial_val="16" label="" + left="24" max_val="2" min_val="0" mouse_opaque="true" + name="WaterUnderWaterFogMod" show_text="true" value="0.25" width="200" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-20" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="245" mouse_opaque="true" name="BDensText" v_pad="0" width="355"> + Reflection Wavelet Scale + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="395" name="WaterNormalScaleHelp" width="18" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-37" drop_shadow_visible="true" follows="left|top|right" + font="SansSerifSmall" h_pad="0" halign="center" height="16" + left="245" mouse_opaque="true" name="BHText2" v_pad="0" width="10"> + 1 + </text> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom_delta="-11" drop_shadow_visible="true" follows="left|top|right" + font="SansSerifSmall" h_pad="0" halign="center" height="16" + left_delta="0" mouse_opaque="true" name="BHText3" v_pad="0" width="10"> + 2 + </text> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom_delta="-11" drop_shadow_visible="true" follows="left|top|right" + font="SansSerifSmall" h_pad="0" halign="center" height="16" + left_delta="0" mouse_opaque="true" name="BHText4" v_pad="0" width="10"> + 3 + </text> + <slider bottom="-50" can_edit_text="false" control_name="WaterNormalScaleX" + decimal_digits="1" follows="left" height="10" increment="0.1" + initial_val="0.7" label="" left="259" max_val="10" min_val="0" + mouse_opaque="true" name="WaterNormalScaleX" show_text="true" value="1.0" + width="200" /> + <slider bottom_delta="-11" can_edit_text="false" control_name="WaterNormalScaleY" + decimal_digits="1" follows="left" height="10" increment="0.1" + initial_val="0.7" label="" left="259" max_val="10" min_val="0" + mouse_opaque="true" name="WaterNormalScaleY" show_text="true" value="1.0" + width="200" /> + <slider bottom_delta="-11" can_edit_text="false" control_name="WaterNormalScaleZ" + decimal_digits="1" follows="left" height="10" increment="0.1" + initial_val="0.7" label="" left="259" max_val="10" min_val="0" + mouse_opaque="true" name="WaterNormalScaleZ" show_text="true" value="1.0" + width="200" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-80" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="245" mouse_opaque="true" name="HDText" v_pad="0" width="355"> + Fresnel Scale + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="395" name="WaterFresnelScaleHelp" width="18" /> + <slider bottom_delta="-30" can_edit_text="false" control_name="WaterFresnelScale" + decimal_digits="2" follows="left" height="10" increment="0.01" + initial_val="0.7" label="" left="259" max_val="1" min_val="0" + mouse_opaque="true" name="WaterFresnelScale" show_text="true" value="1.0" + width="200" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-115" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="245" mouse_opaque="true" name="FresnelOffsetText" v_pad="0" + width="355"> + Fresnel Offset + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="395" name="WaterFresnelOffsetHelp" width="18" /> + <slider bottom_delta="-30" can_edit_text="false" control_name="WaterFresnelOffset" + decimal_digits="2" follows="left" height="10" increment="0.01" + initial_val="0.7" label="" left="259" max_val="1" min_val="0" + mouse_opaque="true" name="WaterFresnelOffset" show_text="true" value="1.0" + width="200" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-20" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="480" mouse_opaque="true" name="DensMultText" v_pad="0" width="355"> + Refract Scale Above + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="630" name="WaterScaleAboveHelp" width="18" /> + <slider bottom_delta="-30" can_edit_text="false" control_name="WaterScaleAbove" + decimal_digits="2" follows="left" height="10" increment="0.01" + initial_val="0.1" label="" left="494" max_val="1" min_val="0" + mouse_opaque="true" name="WaterScaleAbove" show_text="true" value="1.0" + width="200" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-53" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="480" mouse_opaque="true" name="WaterScaleBelowText" v_pad="0" + width="355"> + Refract Scale Below + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="630" name="WaterScaleBelowHelp" width="18" /> + <slider bottom_delta="-30" can_edit_text="false" control_name="WaterScaleBelow" + decimal_digits="2" follows="left" height="10" increment="0.01" + initial_val="0" label="" left="494" max_val="1" min_val="0" + mouse_opaque="true" name="WaterScaleBelow" show_text="true" value="0.0" + width="200" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-87" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="480" mouse_opaque="true" name="MaxAltText" v_pad="0" width="355"> + Blur Multiplier + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="630" name="WaterBlurMultiplierHelp" width="18" /> + <slider bottom_delta="-30" can_edit_text="false" control_name="WaterBlurMult" + decimal_digits="3" follows="left" height="10" increment=".001" + initial_val="0" label="" left="494" max_val=".16" min_val="0" + mouse_opaque="true" name="WaterBlurMult" show_text="true" value="0" + width="200" /> + </panel> + <panel border="true" bottom="-240" follows="left|top|right|bottom" height="180" + label="Image" left="1" mouse_opaque="false" name="Waves" + width="698"> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-20" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="10" mouse_opaque="true" name="BHText" v_pad="0" width="355"> + Big Wave Direction + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="155" name="WaterWave1Help" width="18" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-37" drop_shadow_visible="true" follows="left|top|right" + font="SansSerifSmall" h_pad="0" halign="center" height="16" + left="10" mouse_opaque="true" name="WaterWave1DirXText" v_pad="0" + width="10"> + X + </text> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom_delta="-11" drop_shadow_visible="true" follows="left|top|right" + font="SansSerifSmall" h_pad="0" halign="center" height="16" + left_delta="0" mouse_opaque="true" name="WaterWave1DirYText" v_pad="0" + width="10"> + Y + </text> + <slider bottom="-50" can_edit_text="false" control_name="WaterWave1DirX" + decimal_digits="2" follows="left" height="10" increment="0.01" + initial_val="0.7" label="" left="24" max_val="4" min_val="-4" + mouse_opaque="true" name="WaterWave1DirX" show_text="true" value="0.7" + width="200" /> + <slider bottom_delta="-11" can_edit_text="false" control_name="WaterWave1DirY" + decimal_digits="2" follows="left" height="10" increment="0.01" + initial_val="0.7" label="" left="24" max_val="4" min_val="-4" + mouse_opaque="true" name="WaterWave1DirY" show_text="true" value="0.7" + width="200" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-70" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="10" mouse_opaque="true" name="BHText2" v_pad="0" width="355"> + Little Wave Direction + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="155" name="WaterWave2Help" width="18" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-87" drop_shadow_visible="true" follows="left|top|right" + font="SansSerifSmall" h_pad="0" halign="center" height="16" + left="10" mouse_opaque="true" name="WaterWave2DirXText" v_pad="0" + width="10"> + X + </text> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom_delta="-11" drop_shadow_visible="true" follows="left|top|right" + font="SansSerifSmall" h_pad="0" halign="center" height="16" + left_delta="0" mouse_opaque="true" name="WaterWave2DirYText" v_pad="0" + width="10"> + Y + </text> + <slider bottom="-100" can_edit_text="false" control_name="WaterWave2DirX" + decimal_digits="2" follows="left" height="10" increment="0.01" + initial_val="0.7" label="" left="24" max_val="4" min_val="-4" + mouse_opaque="true" name="WaterWave2DirX" show_text="true" value="0.7" + width="200" /> + <slider bottom_delta="-11" can_edit_text="false" control_name="WaterWave2DirY" + decimal_digits="2" follows="left" height="10" increment="0.01" + initial_val="0.7" label="" left="24" max_val="4" min_val="-4" + mouse_opaque="true" name="WaterWave2DirY" show_text="true" value="0.7" + width="200" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-20" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="240" mouse_opaque="true" name="BHText3" v_pad="0" width="355"> + Normal Map + </text> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="365" name="WaterNormalMapHelp" width="18" /> + <texture_picker bottom="-165" height="143" label="" left="250" name="WaterNormalMap" + width="128" /> + </panel> + </tab_container> + <string name="WLDefaultWaterNames"> + Default:Glassy:Pond:Murky:Second Plague:SNAKE!!!:Valdez + </string> +</floater> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_windlight_manager.xml b/linden/indra/newview/skins/default/xui/en-us/floater_windlight_manager.xml new file mode 100644 index 000000000..9ef70c8d4 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/floater_windlight_manager.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater bottom="-150" can_close="true" can_drag_on_left="false" can_minimize="true" + can_resize="false" height="130" left="50" min_height="130" + min_width="300" mouse_opaque="true" name="WindLight send to server floater" + title="WindLight Manager" + width="300"> + <button bottom="-50" enabled="true" font="SansSerif" halign="center" height="20" + label="This Parcel" label_selected="This Parcel" left="10" + mouse_opaque="true" name="this_parcel" scale_image="true" width="90" /> + <button bottom="-50" enabled="true" font="SansSerif" halign="center" height="20" + label="All Parcels" label_selected="All Parcels" left_delta="95 " + mouse_opaque="true" name="all_parcels" scale_image="true" width="90" /> + <button bottom="-50" enabled="true" font="SansSerif" halign="center" height="20" + label="This Region" label_selected="This Region" left_delta="95 " + mouse_opaque="true" name="this_region" scale_image="true" width="90" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-75" drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="16" + left="10" mouse_opaque="true" name="KeyFramePresetsText" v_pad="0" + width="110"> + Settings: + </text> + <combo_box allow_text_entry="false" bottom="-77" follows="left|top" height="18" + left_delta="70" max_chars="20" mouse_opaque="true" name="WLSettingsCombo" + width="200" /> + <button bottom="-125" enabled="true" font="SansSerif" halign="center" height="20" + label="Show" label_selected="Show" left="10" + mouse_opaque="true" name="show" scale_image="true" width="80" /> + <button bottom="-125" enabled="true" font="SansSerif" halign="center" height="20" + label="Set to Current" label_selected="Set to Current" left="95" + mouse_opaque="true" name="set_to_current" scale_image="true" width="100" /> + <button bottom="-125" enabled="true" font="SansSerif" halign="center" height="20" + label="Remove" label_selected="Remove" left="200" + mouse_opaque="true" name="remove" scale_image="true" width="80" /> +</floater> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_windlight_options.xml b/linden/indra/newview/skins/default/xui/en-us/floater_windlight_options.xml index 4f5fc4adf..c5e2c2aab 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_windlight_options.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_windlight_options.xml @@ -32,6 +32,9 @@ <flyout_button_item value="save_disk_item" name="save_disk_item"> Save to Disk </flyout_button_item> + <flyout_button_item value="send_to_server_item" name="send_to_server_item"> + Send to Server + </flyout_button_item> </flyout_button> <button bottom_delta="0" enabled="true" font="SansSerif" halign="center" height="20" label="Delete File" label_selected="Delete File" right="-10" @@ -211,6 +214,10 @@ initial_val="500" label="" left="494" max_val="4000" min_val="0" mouse_opaque="true" name="WLMaxAltitude" show_text="true" value="4000" width="205" /> + <button bottom="4" enabled="true" font="SansSerif" halign="center" height="20" + label="Day Cycle Editor" label_selected="Day Cycle Editor" + right="-10" mouse_opaque="true" name="WLDayCycleMenuButton" + scale_image="true" width="150" /> </panel> <panel border="true" bottom="-180" follows="left|top|right|bottom" height="160" label="Lighting" left="1" mouse_opaque="true" @@ -572,34 +579,54 @@ mouse_opaque="true" name="WLCloudScrollX" show_text="true" value="0.0" width="200" /> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-60" drop_shadow_visible="true" follows="left|top|right" + bottom="-52" drop_shadow_visible="true" follows="left|top|right" font="SansSerif" h_pad="0" halign="left" height="16" left="480" mouse_opaque="true" name="WLCloudScrollYText" v_pad="0" width="355"> Cloud Scroll Y </text> - <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + <button bottom_delta="-2" follows="left|top" font="SansSerifSmall" height="18" label="?" left="605" name="WLCloudScrollYHelp" width="18" /> <check_box control_name="WLCloudLockY" follows="left" font="SansSerifSmall" height="16" initial_value="false" label="Lock" left="625" mouse_opaque="true" name="WLCloudLockY" width="200" /> - <slider bottom_delta="-15" can_edit_text="false" control_name="WLCloudScrollY" + <slider bottom_delta="-10" can_edit_text="false" control_name="WLCloudScrollY" decimal_digits="2" follows="left" height="10" increment="0.01" initial_val="0.5" label="" left="494" max_val="10" min_val="-10" mouse_opaque="true" name="WLCloudScrollY" show_text="true" value="0.0" width="200" /> - <check_box bottom="-120" control_name="DrawClassicClouds" follows="left" + <check_box bottom="-102" control_name="DrawClassicClouds" follows="left" font="SansSerifSmall" height="16" initial_value="false" label="Draw Classic Clouds" left="480" mouse_opaque="true" name="DrawClassicClouds" width="200" /> - <button bottom="-102" follows="left|top" font="SansSerifSmall" height="18" label="?" + <button bottom="-85" follows="left|top" font="SansSerifSmall" height="18" label="?" left="608" name="WLClassicCloudsHelp" width="18" /> + <text bottom_delta="-19" type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="20" + left="480" mouse_opaque="true" name="WLCloudHeightText" v_pad="0" + width="355"> + Classic Cloud Height + </text> + <slider bottom_delta="-27" can_edit_text="true" control_name="WLCloudHeight" + decimal_digits="0" follows="left" height="16" increment="1" + initial_val="192" label="" left="494" max_val="1000" min_val="0" + mouse_opaque="true" name="WLCloudHeight" show_text="true" value="192" + width="200" /> + <text bottom_delta="0" type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + drop_shadow_visible="true" follows="left|top|right" + font="SansSerif" h_pad="0" halign="left" height="20" + left="480" mouse_opaque="true" name="WLCloudClassicRangeText" v_pad="0" + width="355"> + Classic Cloud Range + </text> + <slider bottom_delta="-27" can_edit_text="true" control_name="WLCloudClassicRange" + decimal_digits="0" follows="left" height="16" increment="1 " + initial_val="48" label="" left="494" max_val="100" min_val="0" + mouse_opaque="true" name="WLCloudRange" show_text="true" value="48" + width="200" /> </panel> </tab_container> - <button bottom="4" enabled="true" font="SansSerif" halign="center" height="20" - label="Day Cycle Editor" label_selected="Day Cycle Editor" - right="-10" mouse_opaque="true" name="WLDayCycleMenuButton" - scale_image="true" width="150" /> <string name="WLDefaultSkyNames"> A-12AM:A-12PM:A-3AM:A-3PM:A-4.30PM:A-6AM:A-6PM:A-9AM:A-9PM:Barcelona:Blizzard:Blue Midday:Coastal Afternoon:Coastal Sunset:Default:Desert Sunset:Fine Day:Fluffy Big Clouds:Foggy:Funky Funky:Funky Funky Funky:Gelatto:Ghost:Incongruent Truths:Midday 1:Midday 2:Midday 3:Midday 4:Night:Pirate:Purple:Sailor's Delight:Sheer Sensuality </string> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_windlight_remote_save.xml b/linden/indra/newview/skins/default/xui/en-us/floater_windlight_remote_save.xml new file mode 100644 index 000000000..84c1d0498 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/floater_windlight_remote_save.xml @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater bottom="-150" can_close="true" can_drag_on_left="false" can_minimize="true" + can_resize="true" height="220" left="50" min_height="220" + min_width="300" mouse_opaque="true" name="WindLight send to server floater" + title="WindLight Send to Server" + width="300"> + <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + left="10" bottom="180" drop_shadow_visible="true" follows="left|top" + font="SansSerif" h_pad="0" halign="left" height="10" + mouse_opaque="true" name="label Type" v_pad="0" width="275"> + WindLight Send to Server + </text> + <slider can_edit_text="true" control_name="max_altitude" + left="20" bottom="110" + decimal_digits="2" follows="left" height="18" increment="0.1" + initial_val="4096.0" label="Max Altitude" max_val="4096.001" min_val="0" + mouse_opaque="true" name="max_altitude" show_text="true" value="4096.0" + width="200" /> + <button follows="left|top" font="SansSerifSmall" height="18" label="?" + left_delta="210" bottom="125" name="max_altitude_help" width="18" enabled="true" /> + + <slider can_edit_text="true" control_name="min_altitude" + left="20" bottom="80" + decimal_digits="2" follows="left" height="18" increment="0.1" + initial_val="1.0" label="Min Altitude" max_val="4096" min_val="0" + mouse_opaque="true" name="min_altitude" show_text="true" value="0" + width="200" /> + <button follows="left|top" font="SansSerifSmall" height="18" label="?" + left_delta="210" bottom="95" name="min_altitude_help" width="18" enabled="true" /> + <slider can_edit_text="true" control_name="Fade" + left="20" bottom="50" + decimal_digits="2" follows="left" height="18" increment="0.1" + initial_val="1.0" label="Fade" max_val="10" min_val="0" + mouse_opaque="true" name="Fade" show_text="true" value="1.0" + width="200" /> + <button follows="left|top" font="SansSerifSmall" height="18" label="?" + left_delta="210" bottom="65" name="fade_help" width="18" /> + + <tab_container bottom="-220" follows="left|top" height="160" left="0" + mouse_opaque="false" name="WindLight_Setting_Types" tab_position="top" width="299"> + <panel border="true" bottom="175" follows="left|top|right|bottom" height="160" + label="Region" left="1" mouse_opaque="false" + name="Region" width="698"> + <check_box control_name="override_parcel" follows="left" font="SansSerifSmall" height="16" + left="20" bottom="30" + initial_value="false" label="Override Parcels" mouse_opaque="true" + name="override_parcel" width="200" enabled="true" /> + <button follows="left|top" font="SansSerifSmall" height="18" label="?" + left_delta="210" bottom="45" name="override_parcel_help" width="18" enabled="true" /> + + <button follows="top|right" font="SansSerif" halign="center" + right="-10" bottom="20" + height="20" label="Send" label_selected="Send" + mouse_opaque="true" name="button_region_send_to_server" scale_image="TRUE" width="78" /> + </panel> + <panel border="true" bottom="175" follows="left|top|right|bottom" height="160" + label="Parcel" left="1" mouse_opaque="false" + name="Parcel" width="698"> + + <!--<slider can_edit_text="true" control_name="max_altitude" + left="20" bottom="110" + decimal_digits="2" follows="left" height="18" increment="0.1" + initial_val="4096.0" label="Max Altitude" max_val="4096.001" min_val="0" + mouse_opaque="true" name="max_altitude" show_text="true" value="4096.0" + width="200" /> + <button follows="left|top" font="SansSerifSmall" height="18" label="?" + left_delta="210" bottom="125" name="max_altitude_help" width="18" enabled="true" /> + + <slider can_edit_text="true" control_name="min_altitude" + left="20" bottom="80" + decimal_digits="2" follows="left" height="18" increment="0.1" + initial_val="1.0" label="Min Altitude" max_val="4096" min_val="0" + mouse_opaque="true" name="min_altitude" show_text="true" value="0" + width="200" /> + <button follows="left|top" font="SansSerifSmall" height="18" label="?" + left_delta="210" bottom="95" name="min_altitude_help" width="18" enabled="true" /> + + <slider can_edit_text="true" control_name="Fade" + left="20" bottom="50" + decimal_digits="2" follows="left" height="18" increment="0.1" + initial_val="1.0" label="Fade" max_val="10" min_val="0" + mouse_opaque="true" name="Fade" show_text="true" value="1.0" + width="200" /> + <button follows="left|top" font="SansSerifSmall" height="18" label="?" + left_delta="210" bottom="65" name="fade_help" width="18" />--> + + <button follows="top|right" font="SansSerif" halign="center" + right="-10" bottom="20" height="20" label="Send" + mouse_opaque="true" name="button_parcel_send_to_server" width="78" /> + </panel> + <!--<panel border="true" bottom="175" follows="left|top|right|bottom" height="160" + label="Area" left="1" mouse_opaque="false" + name="Area" width="698"> + + <slider can_edit_text="true" control_name="Max Altitude" + left="20" bottom="110" + decimal_digits="2" follows="left" height="18" increment="0.1" + initial_val="4096.0" label="Max Altitude" max_val="4096.001" min_val="0" + mouse_opaque="true" name="Max Altitude" show_text="true" value="4096.0" + width="200" /> + <slider can_edit_text="true" control_name="Min Altitude" + left="20" bottom="80" + decimal_digits="2" follows="left" height="18" increment="0.1" + initial_val="1.0" label="Min Altitude" max_val="4096" min_val="0" + mouse_opaque="true" name="Min Altitude" show_text="true" value="0" + width="200" /> + + <slider can_edit_text="true" control_name="Fade" + left="20" bottom="50" + decimal_digits="2" follows="left" height="18" increment="0.1" + initial_val="1.0" label="Fade" max_val="10" min_val="0" + mouse_opaque="true" name="Fade" show_text="true" value="1.0" + width="200" /> + <button follows="left|top" font="SansSerifSmall" height="18" label="?" + left_delta="210" bottom="65" name="fade_help" width="18" /> + + <button follows="top|right" font="SansSerif" halign="center" + right="-10" bottom="20" + height="20" label="Send" label_selected="Send" + mouse_opaque="true" name="button send to server" scale_image="TRUE" width="78" /> + </panel>--> + </tab_container> +</floater> diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_world_map.xml b/linden/indra/newview/skins/default/xui/en-us/floater_world_map.xml index 389efb539..daf217ead 100644 --- a/linden/indra/newview/skins/default/xui/en-us/floater_world_map.xml +++ b/linden/indra/newview/skins/default/xui/en-us/floater_world_map.xml @@ -1,183 +1,183 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater can_close="true" can_drag_on_left="false" can_minimize="true" can_resize="true" - height="711" min_height="520" min_width="410" name="worldmap" - rect_control="FloaterWorldMapRect2" title="World Map" width="1243"> - <tab_container bottom="-701" follows="left|top|right|bottom" height="681" left="15" - mouse_opaque="false" name="maptab" tab_position="top" width="995"> - <panel bottom="-680" follows="left|top|right|bottom" height="664" label="Objects" - left="1" mouse_opaque="true" name="objects_mapview" width="993" /> - <panel bottom="-680" follows="left|top|right|bottom" height="664" label="Terrain" - left="1" mouse_opaque="true" name="terrain_mapview" width="993" /> - </tab_container> - <icon bottom="-50" color="1, 1, 1, 1" follows="top|right" height="16" - image_name="map_avatar_16.tga" left="1013" mouse_opaque="true" name="self" - width="16" /> - <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-50" drop_shadow_visible="true" follows="top|right" - font="SansSerifSmall" h_pad="0" halign="left" height="16" left_delta="20" - mouse_opaque="true" name="you_label" v_pad="0" width="145"> - You - </text> - <icon bottom="-50" color="1, 1, 1, 1" follows="top|right" height="16" - image_name="map_home.tga" left="1083" mouse_opaque="true" name="home" - width="16" /> - <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-50" drop_shadow_visible="true" follows="top|right" - font="SansSerifSmall" h_pad="0" halign="left" height="16" left_delta="20" - mouse_opaque="true" name="home_label" v_pad="0" width="145"> - Home - </text> - <icon bottom="-70" color="0.5, 0.25, 1, 1" follows="top|right" height="16" - image_name="legend.tga" left="1013" mouse_opaque="true" name="square2" - width="16" /> - <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-70" drop_shadow_visible="true" follows="top|right" - font="SansSerifSmall" h_pad="0" halign="left" height="16" left_delta="20" - mouse_opaque="true" name="auction_label" v_pad="0" width="145"> - Auction - </text> - <icon bottom="-70" color="1, 1, 0.25, 1" follows="top|right" height="16" - image_name="legend.tga" left="1083" mouse_opaque="true" name="square" - width="16" /> - <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-70" drop_shadow_visible="true" follows="top|right" - font="SansSerifSmall" h_pad="0" halign="left" height="16" left_delta="20" - mouse_opaque="true" name="land_for_sale_label" v_pad="0" width="145"> - Land For Sale - </text> - <button bottom="-50" follows="top|right" font="SansSerifSmall" halign="center" - height="16" label="Go Home" label_selected="Go Home" left="1150" - mouse_opaque="true" name="Go Home" tool_tip="Teleport to your home" - width="88" /> - <icon bottom="-92" color="0, 1, 0, 1" follows="top|right" height="8" - image_name="map_avatar_8.tga" left="1017" mouse_opaque="true" name="person" - width="8" /> - <check_box bottom="-96" control_name="MapShowPeople" follows="top|right" - font="SansSerifSmall" height="16" initial_value="false" label="Resident" - left_delta="16" mouse_opaque="true" name="people_chk" width="110" /> - <icon bottom="-116" color="1, 1, 1, 1" follows="top|right" height="16" - image_name="map_infohub.tga" left="1013" mouse_opaque="true" name="infohub" - width="16" /> - <check_box bottom="-116" control_name="MapShowInfohubs" follows="top|right" - font="SansSerifSmall" height="16" initial_value="false" label="Infohub" - left_delta="20" mouse_opaque="true" name="infohub_chk" width="110" /> - <icon bottom="-136" color="1, 1, 1, 1" follows="top|right" height="16" - image_name="map_telehub.tga" left="1013" mouse_opaque="true" name="telehub" - width="16" /> - <check_box bottom="-136" control_name="MapShowTelehubs" follows="top|right" - font="SansSerifSmall" height="16" initial_value="false" label="Telehub" - left_delta="20" mouse_opaque="true" name="telehubchk" width="110" /> - <icon bottom="-156" color="1, 1, 1, 1" follows="top|right" height="16" - image_name="icon_for_sale.tga" left="1013" mouse_opaque="true" - name="landforsale" width="16" /> - <check_box bottom="-156" control_name="MapShowLandForSale" follows="top|right" - font="SansSerifSmall" height="16" initial_value="false" label="Land for Sale" - left_delta="20" mouse_opaque="true" name="land_for_sale_chk" width="110" /> - <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-96" drop_shadow_visible="true" follows="top|right" - font="SansSerifSmall" h_pad="0" halign="left" height="16" left="1139" - mouse_opaque="true" name="events_label" v_pad="0" width="145"> - Events: - </text> - <icon bottom="-116" color="1, 1, 1, 1" follows="top|right" height="16" - image_name="map_event.tga" left="1151" mouse_opaque="true" name="event" - width="16" /> - <check_box bottom="-116" control_name="MapShowEvents" follows="top|right" - font="SansSerifSmall" height="16" initial_value="false" label="PG" - left_delta="20" mouse_opaque="true" name="event_chk" width="55" /> - <icon bottom="-136" color="1, 1, 1, 1" follows="top|right" height="16" - image_name="map_event_mature.tga" left="1151" mouse_opaque="true" - name="events_mature_icon" width="16" /> - <check_box bottom="-136" control_name="ShowMatureEvents" follows="top|right" - font="SansSerifSmall" height="16" initial_value="true" label="Mature" - left_delta="20" mouse_opaque="true" name="event_mature_chk" width="55" /> - <icon bottom="-156" color="1, 1, 1, 1" follows="top|right" height="16" - image_name="map_event_adult.tga" left="1151" mouse_opaque="true" - name="events_adult_icon" width="16" /> - <check_box bottom="-156" control_name="ShowAdultEvents" follows="top|right" - font="SansSerifSmall" height="16" initial_value="false" label="Adult" - left_delta="20" mouse_opaque="true" name="event_adult_chk" width="55" /> - <icon bottom="-180" color="0.5, 0, 0, 1" follows="top|right" height="16" - image_name="map_track_16.tga" left="1013" mouse_opaque="true" - name="avatar_icon" width="16" /> - <combo_box allow_text_entry="true" bottom_delta="0" follows="top|right" height="20" - label="Online Friends" left_delta="20" max_chars="60" mouse_opaque="true" - name="friend combo" tool_tip="Friend to Show on Map" width="202"> - <combo_item name="none_selected" value="None"> - Online Friends - </combo_item> - </combo_box> - <icon bottom_delta="-25" color="0.5, 0, 0, 1" follows="top|right" height="16" - image_name="map_track_16.tga" left="1013" mouse_opaque="true" - name="landmark_icon" width="16" /> - <combo_box allow_text_entry="true" bottom_delta="0" follows="top|right" height="20" - label="Landmarks" left_delta="20" max_chars="64" mouse_opaque="true" - name="landmark combo" tool_tip="Landmark to Show on Map" width="202"> - <combo_item name="none_selected" value="None"> - Landmarks - </combo_item> - </combo_box> - <icon bottom_delta="-25" color="0.5, 0, 0, 1" follows="top|right" height="16" - image_name="map_track_16.tga" left="1013" mouse_opaque="true" - name="location_icon" width="16" /> - <line_editor bottom_delta="0" follows="top|right" height="20" label="Search by Region Name" - left_delta="20" name="location" select_on_focus="true" - tool_tip="Type the name of a region" width="140" /> - <button bottom_delta="0" follows="top|right" font="SansSerif" halign="center" - height="20" label="Search" left_delta="145" mouse_opaque="true" - name="DoSearch" tool_tip="Search for region" width="60" /> - <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom_delta="-20" drop_shadow_visible="true" follows="top|right" - font="SansSerif" h_pad="0" halign="left" height="16" left="1013" - mouse_opaque="true" name="search_label" v_pad="0" width="222"> - Search Results: - </text> - <scroll_list background_visible="true" bottom_delta="-326" draw_border="true" - draw_stripes="false" - follows="top|right|bottom" height="320" left="1013" multi_select="false" - name="search_results" width="222"> - <column label="" name="icon" width="16" /> - <column label="" name="sim_name" width="206" /> - </scroll_list> - <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom_delta="-20" drop_shadow_visible="true" follows="bottom|right" - font="SansSerif" h_pad="0" halign="left" height="16" left="1013" - mouse_opaque="true" name="location_label" v_pad="0" width="98"> - Location: - </text> - <spinner bottom_delta="0" decimal_digits="0" follows="bottom|right" height="16" - increment="1" initial_val="128" left="1090" max_val="255" min_val="0" - mouse_opaque="true" name="spin x" - tool_tip="X coordinate of location to show on map" width="48" /> - <spinner bottom_delta="0" decimal_digits="0" follows="bottom|right" height="16" - increment="1" initial_val="128" left_delta="50" max_val="255" min_val="0" - mouse_opaque="true" name="spin y" - tool_tip="Y coordinate of location to show on map" width="48" /> - <spinner bottom_delta="0" decimal_digits="0" follows="bottom|right" height="16" - increment="1" initial_val="0" left_delta="50" max_val="4096" min_val="0" - mouse_opaque="true" name="spin z" - tool_tip="Z coordinate of location to show on map" width="48" /> - <button bottom="-625" follows="right|bottom" font="SansSerif" halign="center" - height="20" label="Teleport" label_selected="Teleport" left="-230" - mouse_opaque="true" name="Teleport" - tool_tip="Teleport to selected location" width="90" /> - <button bottom_delta="0" follows="right|bottom" font="SansSerif" halign="center" - height="20" label="Show Destination" label_selected="Show Destination" - left_delta="100" mouse_opaque="true" name="Show Destination" - tool_tip="Center map on selected location" width="125" /> - <button bottom_delta="-24" follows="right|bottom" font="SansSerif" halign="center" - height="20" label="Clear" label_selected="Clear" left="-230" - mouse_opaque="true" name="Clear" tool_tip="Stop tracking" width="90" /> - <button bottom_delta="0" follows="right|bottom" font="SansSerif" halign="center" - height="20" label="Show My Location" label_selected="Show My Location" - left_delta="100" mouse_opaque="true" name="Show My Location" - tool_tip="Center map on your avatar's location" width="125" /> - <button bottom_delta="-24" enabled="false" follows="bottom|right" font="SansSerif" - height="20" label="Copy SLURL to clipboard" left="-230" name="copy_slurl" - tool_tip="Copies current location as SLURL to be used on the web." - width="222" /> - <slider bottom="-697" can_edit_text="false" decimal_digits="3" follows="right|bottom" - height="16" increment="0.2" initial_val="48.5029" label="Zoom" left="-230" - max_val="0" min_val="-8" mouse_opaque="true" name="zoom slider" - show_text="false" value="48.5029" width="222" /> -</floater> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater can_close="true" can_drag_on_left="false" can_minimize="true" can_resize="true" + height="711" min_height="520" min_width="410" name="worldmap" + rect_control="FloaterWorldMapRect2" title="World Map" width="1243"> + <tab_container bottom="-701" follows="left|top|right|bottom" height="681" left="15" + mouse_opaque="false" name="maptab" tab_position="top" width="995"> + <panel bottom="-680" follows="left|top|right|bottom" height="664" label="Objects" + left="1" mouse_opaque="true" name="objects_mapview" width="993" /> + <panel bottom="-680" follows="left|top|right|bottom" height="664" label="Terrain" + left="1" mouse_opaque="true" name="terrain_mapview" width="993" /> + </tab_container> + <icon bottom="-50" color="1, 1, 1, 1" follows="top|right" height="16" + image_name="map_avatar_16.tga" left="1013" mouse_opaque="true" name="self" + width="16" /> + <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-50" drop_shadow_visible="true" follows="top|right" + font="SansSerifSmall" h_pad="0" halign="left" height="16" left_delta="20" + mouse_opaque="true" name="you_label" v_pad="0" width="145"> + You + </text> + <icon bottom="-50" color="1, 1, 1, 1" follows="top|right" height="16" + image_name="map_home.tga" left="1083" mouse_opaque="true" name="home" + width="16" /> + <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-50" drop_shadow_visible="true" follows="top|right" + font="SansSerifSmall" h_pad="0" halign="left" height="16" left_delta="20" + mouse_opaque="true" name="home_label" v_pad="0" width="145"> + Home + </text> + <icon bottom="-70" color="0.5, 0.25, 1, 1" follows="top|right" height="16" + image_name="legend.tga" left="1013" mouse_opaque="true" name="square2" + width="16" /> + <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-70" drop_shadow_visible="true" follows="top|right" + font="SansSerifSmall" h_pad="0" halign="left" height="16" left_delta="20" + mouse_opaque="true" name="auction_label" v_pad="0" width="145"> + Auction + </text> + <icon bottom="-70" color="1, 1, 0.25, 1" follows="top|right" height="16" + image_name="legend.tga" left="1083" mouse_opaque="true" name="square" + width="16" /> + <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-70" drop_shadow_visible="true" follows="top|right" + font="SansSerifSmall" h_pad="0" halign="left" height="16" left_delta="20" + mouse_opaque="true" name="land_for_sale_label" v_pad="0" width="145"> + Land For Sale + </text> + <button bottom="-50" follows="top|right" font="SansSerifSmall" halign="center" + height="16" label="Go Home" label_selected="Go Home" left="1150" + mouse_opaque="true" name="Go Home" tool_tip="Teleport to your home" + width="88" /> + <icon bottom="-92" color="0, 1, 0, 1" follows="top|right" height="8" + image_name="map_avatar_8.tga" left="1017" mouse_opaque="true" name="person" + width="8" /> + <check_box bottom="-96" control_name="MapShowPeople" follows="top|right" + font="SansSerifSmall" height="16" initial_value="false" label="Resident" + left_delta="16" mouse_opaque="true" name="people_chk" width="110" /> + <icon bottom="-116" color="1, 1, 1, 1" follows="top|right" height="16" + image_name="map_infohub.tga" left="1013" mouse_opaque="true" name="infohub" + width="16" /> + <check_box bottom="-116" control_name="MapShowInfohubs" follows="top|right" + font="SansSerifSmall" height="16" initial_value="false" label="Infohub" + left_delta="20" mouse_opaque="true" name="infohub_chk" width="110" /> + <icon bottom="-136" color="1, 1, 1, 1" follows="top|right" height="16" + image_name="map_telehub.tga" left="1013" mouse_opaque="true" name="telehub" + width="16" /> + <check_box bottom="-136" control_name="MapShowTelehubs" follows="top|right" + font="SansSerifSmall" height="16" initial_value="false" label="Telehub" + left_delta="20" mouse_opaque="true" name="telehubchk" width="110" /> + <icon bottom="-156" color="1, 1, 1, 1" follows="top|right" height="16" + image_name="icon_for_sale.tga" left="1013" mouse_opaque="true" + name="landforsale" width="16" /> + <check_box bottom="-156" control_name="MapShowLandForSale" follows="top|right" + font="SansSerifSmall" height="16" initial_value="false" label="Land for Sale" + left_delta="20" mouse_opaque="true" name="land_for_sale_chk" width="110" /> + <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-96" drop_shadow_visible="true" follows="top|right" + font="SansSerifSmall" h_pad="0" halign="left" height="16" left="1139" + mouse_opaque="true" name="events_label" v_pad="0" width="145"> + Events: + </text> + <icon bottom="-116" color="1, 1, 1, 1" follows="top|right" height="16" + image_name="map_event.tga" left="1151" mouse_opaque="true" name="event" + width="16" /> + <check_box bottom="-116" control_name="MapShowEvents" follows="top|right" + font="SansSerifSmall" height="16" initial_value="false" label="PG" + left_delta="20" mouse_opaque="true" name="event_chk" width="55" /> + <icon bottom="-136" color="1, 1, 1, 1" follows="top|right" height="16" + image_name="map_event_mature.tga" left="1151" mouse_opaque="true" + name="events_mature_icon" width="16" /> + <check_box bottom="-136" control_name="ShowMatureEvents" follows="top|right" + font="SansSerifSmall" height="16" initial_value="true" label="Mature" + left_delta="20" mouse_opaque="true" name="event_mature_chk" width="55" /> + <icon bottom="-156" color="1, 1, 1, 1" follows="top|right" height="16" + image_name="map_event_adult.tga" left="1151" mouse_opaque="true" + name="events_adult_icon" width="16" /> + <check_box bottom="-156" control_name="ShowAdultEvents" follows="top|right" + font="SansSerifSmall" height="16" initial_value="false" label="Adult" + left_delta="20" mouse_opaque="true" name="event_adult_chk" width="55" /> + <icon bottom="-180" color="0.5, 0, 0, 1" follows="top|right" height="16" + image_name="map_track_16.tga" left="1013" mouse_opaque="true" + name="avatar_icon" width="16" /> + <combo_box allow_text_entry="true" bottom_delta="0" follows="top|right" height="20" + label="Online Friends" left_delta="20" max_chars="60" mouse_opaque="true" + name="friend combo" tool_tip="Friend to Show on Map" width="202"> + <combo_item name="none_selected" value="None"> + Online Friends + </combo_item> + </combo_box> + <icon bottom_delta="-25" color="0.5, 0, 0, 1" follows="top|right" height="16" + image_name="map_track_16.tga" left="1013" mouse_opaque="true" + name="landmark_icon" width="16" /> + <combo_box allow_text_entry="true" bottom_delta="0" follows="top|right" height="20" + label="Landmarks" left_delta="20" max_chars="64" mouse_opaque="true" + name="landmark combo" tool_tip="Landmark to Show on Map" width="202"> + <combo_item name="none_selected" value="None"> + Landmarks + </combo_item> + </combo_box> + <icon bottom_delta="-25" color="0.5, 0, 0, 1" follows="top|right" height="16" + image_name="map_track_16.tga" left="1013" mouse_opaque="true" + name="location_icon" width="16" /> + <line_editor bottom_delta="0" follows="top|right" height="20" label="Search by Region Name" + left_delta="20" name="location" select_on_focus="true" + tool_tip="Type the name of a region" width="140" /> + <button bottom_delta="0" follows="top|right" font="SansSerif" halign="center" + height="20" label="Search" left_delta="145" mouse_opaque="true" + name="DoSearch" tool_tip="Search for region" width="60" /> + <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom_delta="-20" drop_shadow_visible="true" follows="top|right" + font="SansSerif" h_pad="0" halign="left" height="16" left="1013" + mouse_opaque="true" name="search_label" v_pad="0" width="222"> + Search Results: + </text> + <scroll_list background_visible="true" bottom_delta="-326" draw_border="true" + draw_stripes="false" + follows="top|right|bottom" height="320" left="1013" multi_select="false" + name="search_results" width="222"> + <column label="" name="icon" width="16" /> + <column label="" name="sim_name" width="206" /> + </scroll_list> + <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom_delta="-20" drop_shadow_visible="true" follows="bottom|right" + font="SansSerif" h_pad="0" halign="left" height="16" left="1013" + mouse_opaque="true" name="location_label" v_pad="0" width="98"> + Location: + </text> + <spinner bottom_delta="0" decimal_digits="0" follows="bottom|right" height="16" + increment="1" initial_val="128" left="1090" max_val="99999" min_val="0" + mouse_opaque="true" name="spin x" + tool_tip="X coordinate of location to show on map" width="48" /> + <spinner bottom_delta="0" decimal_digits="0" follows="bottom|right" height="16" + increment="1" initial_val="128" left_delta="50" max_val="99999" min_val="0" + mouse_opaque="true" name="spin y" + tool_tip="Y coordinate of location to show on map" width="48" /> + <spinner bottom_delta="0" decimal_digits="0" follows="bottom|right" height="16" + increment="1" initial_val="0" left_delta="50" max_val="4096" min_val="0" + mouse_opaque="true" name="spin z" + tool_tip="Z coordinate of location to show on map" width="48" /> + <button bottom="-625" follows="right|bottom" font="SansSerif" halign="center" + height="20" label="Teleport" label_selected="Teleport" left="-230" + mouse_opaque="true" name="Teleport" + tool_tip="Teleport to selected location" width="90" /> + <button bottom_delta="0" follows="right|bottom" font="SansSerif" halign="center" + height="20" label="Show Destination" label_selected="Show Destination" + left_delta="100" mouse_opaque="true" name="Show Destination" + tool_tip="Center map on selected location" width="125" /> + <button bottom_delta="-24" follows="right|bottom" font="SansSerif" halign="center" + height="20" label="Clear" label_selected="Clear" left="-230" + mouse_opaque="true" name="Clear" tool_tip="Stop tracking" width="90" /> + <button bottom_delta="0" follows="right|bottom" font="SansSerif" halign="center" + height="20" label="Show My Location" label_selected="Show My Location" + left_delta="100" mouse_opaque="true" name="Show My Location" + tool_tip="Center map on your avatar's location" width="125" /> + <button bottom_delta="-24" enabled="false" follows="bottom|right" font="SansSerif" + height="20" label="Copy SLURL to clipboard" left="-230" name="copy_slurl" + tool_tip="Copies current location as SLURL to be used on the web." + width="222" /> + <slider bottom="-697" can_edit_text="false" decimal_digits="3" follows="right|bottom" + height="16" increment="0.2" initial_val="48.5029" label="Zoom" left="-230" + max_val="0" min_val="-8" mouse_opaque="true" name="zoom slider" + show_text="false" value="48.5029" width="222" /> +</floater> diff --git a/linden/indra/newview/skins/default/xui/en-us/fonts.xml b/linden/indra/newview/skins/default/xui/en-us/fonts.xml index 556407944..7343ac210 100644 --- a/linden/indra/newview/skins/default/xui/en-us/fonts.xml +++ b/linden/indra/newview/skins/default/xui/en-us/fonts.xml @@ -153,7 +153,7 @@ /> <font_size name="Small" comment="Size of small font (points, or 1/72 of an inch)" - size="8" + size="8.5" /> </fonts> diff --git a/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_attachment.xml b/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_attachment.xml index 18bedd0b5..ffdae9b32 100644 --- a/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_attachment.xml +++ b/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_attachment.xml @@ -1,23 +1,23 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<pie_menu name="Attachment Pie"> - <menu_item_call enabled="false" label="Drop" mouse_opaque="true" name="Drop"> - <on_click function="Attachment.Drop" /> - <on_enable function="Attachment.EnableDrop" /> - </menu_item_call> - <menu_item_separator /> - <menu_item_separator /> - <menu_item_separator /> - <menu_item_call enabled="true" label="Inspect" mouse_opaque="true" name="Object Inspect"> - <on_click function="Object.Inspect" /> - <on_enable function="Object.EnableInspect" /> - </menu_item_call> - <menu_item_separator /> - <menu_item_call enabled="false" label="Detach" mouse_opaque="true" name="Detach"> - <on_click function="Attachment.Detach" /> - <on_enable function="Attachment.EnableDetach" /> - </menu_item_call> - <menu_item_call enabled="false" label="Edit..." mouse_opaque="true" name="Edit"> - <on_click function="Object.Edit" /> - <on_enable function="EnableEdit" /> - </menu_item_call> -</pie_menu> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<pie_menu name="Attachment Pie" moonworld="true"> + <menu_item_call enabled="false" label="Drop" mouse_opaque="true" name="Drop"> + <on_click function="Attachment.Drop" /> + <on_enable function="Attachment.EnableDrop" /> + </menu_item_call> + <menu_item_separator /> + <menu_item_separator /> + <menu_item_separator /> + <menu_item_call enabled="true" label="Inspect" mouse_opaque="true" name="Object Inspect"> + <on_click function="Object.Inspect" /> + <on_enable function="Object.EnableInspect" /> + </menu_item_call> + <menu_item_separator /> + <menu_item_call enabled="false" label="Detach" mouse_opaque="true" name="Detach" moonworld="true"> + <on_click function="Attachment.Detach" /> + <on_enable function="Attachment.EnableDetach" /> + </menu_item_call> + <menu_item_call enabled="false" label="Edit..." mouse_opaque="true" name="Edit"> + <on_click function="Object.Edit" /> + <on_enable function="EnableEdit" /> + </menu_item_call> +</pie_menu> diff --git a/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_avatar.xml b/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_avatar.xml index dcf752157..0ad035448 100644 --- a/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_avatar.xml +++ b/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_avatar.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<pie_menu name="Avatar Pie"> +<pie_menu name="Avatar Pie" moonworld="false"> <menu_item_call enabled="false" label="Profile" mouse_opaque="true" name="Profile"> <on_click function="ShowAgentProfile" userdata="hit object" /> </menu_item_call> diff --git a/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_land.xml b/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_land.xml index 766ad1b7c..87cf6193e 100644 --- a/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_land.xml +++ b/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_land.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<pie_menu name="Land Pie"> +<pie_menu name="Land Pie" moonworld="false"> <menu_item_call enabled="false" label="About Land" mouse_opaque="true" name="About Land"> <on_click function="ShowFloater" userdata="about land" /> </menu_item_call> diff --git a/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_object.xml b/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_object.xml index ff142b599..f1431a117 100644 --- a/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_object.xml +++ b/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_object.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<pie_menu name="Object Pie"> +<pie_menu name="Object Pie" moonworld="true"> <menu_item_call enabled="false" label="Open" mouse_opaque="true" name="Open"> <on_click function="Object.Open" /> <on_enable function="Object.EnableOpen" /> @@ -8,11 +8,11 @@ <on_click function="Object.Build" /> <on_enable function="EnableEdit" /> </menu_item_call> - <menu_item_call enabled="false" label="Touch" mouse_opaque="true" name="Object Touch"> + <menu_item_call enabled="false" label="Touch" mouse_opaque="true" name="Object Touch" moonworld="true"> <on_click function="Object.Touch" /> <on_enable function="Object.EnableTouch" userdata="Touch" name="EnableTouch"/> </menu_item_call> - <menu_item_call enabled="false" label="Sit Here" mouse_opaque="true" name="Object Sit"> + <menu_item_call enabled="false" label="Sit Here" mouse_opaque="true" name="Object Sit" moonworld="true"> <on_click function="Object.SitOrStand" /> <on_enable function="Object.EnableSitOrStand" userdata="Sit Here,Stand Up" name="EnableSitOrStand"/> </menu_item_call> diff --git a/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_self.xml b/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_self.xml index d6409bfd1..cf7f93c1d 100644 --- a/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_self.xml +++ b/linden/indra/newview/skins/default/xui/en-us/legacy_menu_pie_self.xml @@ -1,22 +1,22 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <pie_menu name="Self Pie"> - <menu_item_call enabled="true" label="Profile..." name="Profile..."> + <menu_item_call enabled="true" label="Profile..." name="Profile..." moonworld="false"> <on_click function="ShowAgentProfile" userdata="agent" /> </menu_item_call> - <menu_item_call enabled="true" label="Groups" name="Groups"> + <menu_item_call enabled="true" label="Groups" name="Groups" moonworld="false"> <on_click function="ShowAgentGroups" userdata="agent" /> </menu_item_call> - <menu_item_call enabled="true" label="Inventory" name="Inventory"> + <menu_item_call enabled="true" label="Inventory" name="Inventory" moonworld="false"> <on_click function="ShowFloater" userdata="inventory" /> </menu_item_call> - <menu_item_call enabled="true" label="Stand Up" name="Stand Up"> + <menu_item_call enabled="true" label="Stand Up" name="Stand Up" moonworld="false"> <on_click function="Self.StandUp" userdata="" /> <on_enable function="Self.EnableStandUp" /> </menu_item_call> - <menu_item_call enabled="true" label="Friends" name="Friends"> + <menu_item_call enabled="true" label="Friends" name="Friends" moonworld="false"> <on_click function="ShowFloater" userdata="friends" /> </menu_item_call> - <menu_item_call enabled="true" label="Gestures" name="Gestures"> + <menu_item_call enabled="true" label="Gestures" name="Gestures" moonworld="false"> <on_click function="ShowFloater" userdata="gestures" /> </menu_item_call> <pie_menu enabled="true" label="Take Off >" name="Take Off >"> @@ -84,16 +84,16 @@ </menu_item_call> </pie_menu> <menu_item_separator /> - <pie_menu enabled="true" label="HUD >" name="Object Detach HUD" /> + <pie_menu enabled="true" label="HUD >" name="Object Detach HUD" moonworld="false" /> <menu_item_separator /> - <pie_menu enabled="true" label="Detach >" name="Object Detach" /> + <pie_menu enabled="true" label="Detach >" name="Object Detach" moonworld="false" /> <menu_item_separator /> <menu_item_call enabled="true" label="Detach All" name="Detach All"> <on_click function="Self.RemoveAllAttachments" userdata="" /> <on_enable function="Self.EnableRemoveAllAttachments" /> </menu_item_call> </pie_menu> - <menu_item_call enabled="true" label="Appearance..." name="Appearance..."> + <menu_item_call enabled="true" label="Appearance..." name="Appearance..." moonworld="false"> <on_click function="ShowFloater" userdata="appearance" /> <on_enable function="Edit.EnableCustomizeAvatar" /> </menu_item_call> diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_areasearch.xml b/linden/indra/newview/skins/default/xui/en-us/menu_areasearch.xml new file mode 100644 index 000000000..c55d1b36a --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/menu_areasearch.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<menu bottom="100" color="MenuDefaultBgColor" drop_shadow="true" height="101" left="100" + mouse_opaque="false" name="popup" opaque="true" width="128"> + <menu_item_call bottom_delta="-18" height="18" label="Teleport to" left="0" + mouse_opaque="true" name="teleport" width="128"> + <on_click function="Popup.HandleMenu" userdata="teleport" /> + </menu_item_call> + <menu_item_call bottom_delta="-18" height="18" label="Cam to" left="0" + mouse_opaque="true" name="cam" width="128"> + <on_click function="Popup.HandleMenu" userdata="cam" /> + </menu_item_call> + <menu_item_call bottom_delta="-18" height="18" label="Edit" left="0" + mouse_opaque="true" name="edit" width="128"> + <on_click function="Popup.HandleMenu" userdata="edit" /> + </menu_item_call> +</menu> diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_inventory.xml b/linden/indra/newview/skins/default/xui/en-us/menu_inventory.xml index 1ae746590..86dc5c737 100644 --- a/linden/indra/newview/skins/default/xui/en-us/menu_inventory.xml +++ b/linden/indra/newview/skins/default/xui/en-us/menu_inventory.xml @@ -166,11 +166,15 @@ <on_click filter="" function="Inventory.DoToSelected" userdata="copy_uuid" /> </menu_item_call> <menu_item_separator name="Copy Separator" /> - <menu_item_call bottom_delta="-18" height="18" label="Copy" left="0" mouse_opaque="true" + <menu_item_call bottom_delta="-18" height="18" label="Cut" left="0" mouse_opaque="true" + name="Cut" width="128"> + <on_click filter="" function="Inventory.DoToSelected" userdata="cut" /> + </menu_item_call> + <menu_item_call bottom_delta="-18" height="18" label="Copy" left="0" mouse_opaque="true" name="Copy" width="128"> - <on_click filter="" function="Inventory.DoToSelected" userdata="copy" /> - </menu_item_call> - <menu_item_call bottom_delta="-18" height="18" label="Paste" left="0" mouse_opaque="true" + <on_click filter="" function="Inventory.DoToSelected" userdata="copy" /> + </menu_item_call> + <menu_item_call bottom_delta="-18" height="18" label="Paste" left="0" mouse_opaque="true" name="Paste" width="128"> <on_click filter="" function="Inventory.DoToSelected" userdata="paste" /> </menu_item_call> diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_login.xml b/linden/indra/newview/skins/default/xui/en-us/menu_login.xml index d9a9c4cde..292c9b033 100644 --- a/linden/indra/newview/skins/default/xui/en-us/menu_login.xml +++ b/linden/indra/newview/skins/default/xui/en-us/menu_login.xml @@ -1,13 +1,13 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<menu_bar name="Login Menu" opaque="true" tear_off="false"> - <menu create_jump_keys="true" label="File" name="File" opaque="true" tear_off="false"> - <menu_item_call label="Quit" name="Quit" shortcut="control|Q"> +<menu_bar name="Login Menu" opaque="true" tear_off="false" height="18" bottom="-18" moonworld="true"> + <menu create_jump_keys="true" label="File" name="File" opaque="true" tear_off="false" moonworld="true"> + <menu_item_call label="Quit" name="Quit" shortcut="control|Q" moonworld="true"> <on_click function="File.Quit" userdata="" /> </menu_item_call> </menu> - <menu create_jump_keys="true" label="Edit" name="Edit" + <menu create_jump_keys="true" label="Edit" name="Edit" moonworld="true" opaque="true" tear_off="false"> - <menu_item_call label="Preferences..." name="Preferences..." shortcut="control|P"> + <menu_item_call label="Preferences..." name="Preferences..." shortcut="control|P" moonworld="true"> <on_click function="ShowFloater" userdata="preferences" /> </menu_item_call> </menu> diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_pie_attachment.xml b/linden/indra/newview/skins/default/xui/en-us/menu_pie_attachment.xml index 439728564..200795616 100644 --- a/linden/indra/newview/skins/default/xui/en-us/menu_pie_attachment.xml +++ b/linden/indra/newview/skins/default/xui/en-us/menu_pie_attachment.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<pie_menu name="Attachment Pie"> +<pie_menu name="Attachment Pie" moonworld="true"> <menu_item_call enabled="true" label="Profile..." name="Profile..."> <on_click function="ShowAgentProfile" userdata="agent" /> </menu_item_call> @@ -21,13 +21,13 @@ <on_click function="ShowFloater" userdata="appearance" /> <on_enable function="Edit.EnableCustomizeAvatar" /> </menu_item_call> - <pie_menu label="More >" name="More >"> + <pie_menu label="More >" name="More >" moonworld="true"> <menu_item_call enabled="false" label="Drop" mouse_opaque="true" name="Drop"> <on_click function="Attachment.Drop" /> <on_enable function="Attachment.EnableDrop" /> </menu_item_call> <menu_item_separator /> - <menu_item_call enabled="false" label="Detach" mouse_opaque="true" name="Detach"> + <menu_item_call enabled="false" label="Detach" mouse_opaque="true" name="Detach" moonworld="true"> <on_click function="Attachment.Detach" /> <on_enable function="Attachment.EnableDetach" /> </menu_item_call> diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml b/linden/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml index c87d7de8d..134b82b29 100644 --- a/linden/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml +++ b/linden/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<pie_menu name="Avatar Pie"> +<pie_menu name="Avatar Pie" moonworld="false"> <menu_item_call enabled="false" label="Profile" mouse_opaque="true" name="Profile"> <on_click function="ShowAgentProfile" userdata="hit object" /> </menu_item_call> diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_pie_hud.xml b/linden/indra/newview/skins/default/xui/en-us/menu_pie_hud.xml index 64bb77945..967c6c0f6 100644 --- a/linden/indra/newview/skins/default/xui/en-us/menu_pie_hud.xml +++ b/linden/indra/newview/skins/default/xui/en-us/menu_pie_hud.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <pie_menu name="HUD Pie"> - <menu_item_call enabled="false" label="Drop" mouse_opaque="true" name="Drop"> + <menu_item_call enabled="false" label="Drop" mouse_opaque="true" name="Drop" moonworld="false"> <on_click function="Attachment.Drop" /> <on_enable function="Attachment.EnableDrop" /> </menu_item_call> @@ -10,7 +10,7 @@ <on_enable function="Attachment.EnableTouch" userdata="Touch" /> </menu_item_call> <menu_item_separator /> - <menu_item_call enabled="true" label="Inspect" mouse_opaque="true" name="Object Inspect"> + <menu_item_call enabled="true" label="Inspect" mouse_opaque="true" name="Object Inspect" moonworld="false"> <on_click function="Object.Inspect" /> <on_enable function="Object.EnableInspect" /> </menu_item_call> diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_pie_land.xml b/linden/indra/newview/skins/default/xui/en-us/menu_pie_land.xml index af3fcd620..27772268f 100644 --- a/linden/indra/newview/skins/default/xui/en-us/menu_pie_land.xml +++ b/linden/indra/newview/skins/default/xui/en-us/menu_pie_land.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<pie_menu name="Land Pie"> +<pie_menu name="Land Pie" moonworld="false"> <menu_item_call enabled="false" label="About Land" mouse_opaque="true" name="About Land"> <on_click function="ShowFloater" userdata="about land" /> </menu_item_call> diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_pie_object.xml b/linden/indra/newview/skins/default/xui/en-us/menu_pie_object.xml index ec828dfde..97f9dbc65 100644 --- a/linden/indra/newview/skins/default/xui/en-us/menu_pie_object.xml +++ b/linden/indra/newview/skins/default/xui/en-us/menu_pie_object.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<pie_menu name="Object Pie"> +<pie_menu name="Object Pie" moonworld="true"> <menu_item_call enabled="false" label="Open" mouse_opaque="true" name="Open"> <on_click function="Object.Open" /> <on_enable function="Object.EnableOpen" /> @@ -8,11 +8,11 @@ <on_click function="Object.Buy" /> <on_enable function="Object.EnableBuy" /> </menu_item_call> - <menu_item_call enabled="false" label="Touch" mouse_opaque="true" name="Object Touch"> + <menu_item_call enabled="false" label="Touch" mouse_opaque="true" name="Object Touch" moonworld="true"> <on_click function="Object.Touch" /> <on_enable function="Object.EnableTouch" userdata="Touch" name="EnableTouch"/> </menu_item_call> - <menu_item_call enabled="false" label="Sit Here" mouse_opaque="true" name="Object Sit"> + <menu_item_call enabled="false" label="Sit Here" mouse_opaque="true" name="Object Sit" moonworld="true"> <on_click function="Object.SitOrStand" /> <on_enable function="Object.EnableSitOrStand" userdata="Sit Here,Stand Up" name="EnableSitOrStand"/> </menu_item_call> diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_pie_self.xml b/linden/indra/newview/skins/default/xui/en-us/menu_pie_self.xml index b8d69dad0..fe2d6223a 100644 --- a/linden/indra/newview/skins/default/xui/en-us/menu_pie_self.xml +++ b/linden/indra/newview/skins/default/xui/en-us/menu_pie_self.xml @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <pie_menu name="Self Pie"> - <menu_item_call enabled="true" label="Profile..." name="Profile..."> + <menu_item_call enabled="true" label="Profile..." name="Profile..." moonworld="false"> <on_click function="ShowAgentProfile" userdata="agent" /> </menu_item_call> - <menu_item_call enabled="true" label="Groups" name="Groups"> + <menu_item_call enabled="true" label="Groups" name="Groups" moonworld="false"> <on_click function="ShowAgentGroups" userdata="agent" /> </menu_item_call> <menu_item_separator /> @@ -11,10 +11,10 @@ <on_click function="Self.StandUp" userdata="" /> <on_enable function="Self.EnableStandUp" /> </menu_item_call> - <menu_item_call enabled="true" label="Friends" name="Friends"> + <menu_item_call enabled="true" label="Friends" name="Friends" moonworld="false"> <on_click function="ShowFloater" userdata="friends" /> </menu_item_call> - <menu_item_call enabled="true" label="Appearance..." name="Appearance..."> + <menu_item_call enabled="true" label="Appearance..." name="Appearance..." moonworld="false"> <on_click function="ShowFloater" userdata="appearance" /> <on_enable function="Edit.EnableCustomizeAvatar" /> </menu_item_call> @@ -88,9 +88,9 @@ <on_enable function="Self.EnableRemoveAllAttachments" /> </menu_item_call> <menu_item_separator /> - <pie_menu enabled="true" label="Detach >" name="Object Detach" /> + <pie_menu enabled="true" label="Detach >" name="Object Detach" moonworld="false" /> <menu_item_separator /> - <pie_menu enabled="true" label="HUD >" name="Object Detach HUD" /> + <pie_menu enabled="true" label="HUD >" name="Object Detach HUD" moonworld="false" /> <menu_item_separator /> </pie_menu> <menu_item_separator /> diff --git a/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml b/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml index c85dd4727..8045f8ca6 100644 --- a/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml +++ b/linden/indra/newview/skins/default/xui/en-us/menu_viewer.xml @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<menu_bar name="Main Menu" drop_shadow="false" follows="left|top|right" +<menu_bar name="Main Menu" drop_shadow="false" follows="left|top|right" moonworld="true" opaque="false" tear_off="false"> <!-- FILE --> - <menu name="File" create_jump_keys="true" label="File" + <menu name="File" create_jump_keys="true" label="File" moonworld="true" opaque="true" tear_off="true"> <menu label="Upload" create_jump_keys="true" name="Upload" opaque="true" tear_off="true"> @@ -80,19 +80,19 @@ <on_enable function="File.EnableSaveAs" /> </menu_item_call> <menu_item_separator /> - <menu_item_call name="Take Snapshot" + <menu_item_call name="Take Snapshot" moonworld="true" label="Take Snapshot" shortcut="control|shift|S"> <on_click function="File.TakeSnapshot" userdata="" /> </menu_item_call> - <menu_item_call name="Snapshot to Disk" + <menu_item_call name="Snapshot to Disk" moonworld="true" label="Snapshot to Disk" shortcut="control|`" useMacCtrl="true"> <on_click function="File.TakeSnapshotToDisk" userdata="" /> </menu_item_call> - <menu_item_separator /> - <menu_item_call name="Quit" label="Quit" + <menu_item_separator moonworld="true" /> + <menu_item_call name="Quit" label="Quit" moonworld="true" shortcut="control|Q"> <on_click function="File.Quit" userdata="" /> </menu_item_call> @@ -102,7 +102,7 @@ <!-- EDIT --> - <menu name="Edit" create_jump_keys="true" label="Edit" + <menu name="Edit" create_jump_keys="true" label="Edit" moonworld="true" opaque="true" tear_off="true"> <menu_item_call name="Undo" enabled="false" label="Undo" shortcut="control|Z"> @@ -267,12 +267,13 @@ <on_check function="FloaterVisible" userdata="friends" /> </menu_item_check> - <menu_item_call name="Groups" label="Groups"> + <menu_item_call name="Groups" label="Groups" + shortcut="control|shift|G"> <on_click function="ShowAgentGroups" userdata="agent" /> </menu_item_call> <menu_item_separator /> - <menu_item_call name="Preferences..." label="Preferences..." + <menu_item_call name="Preferences..." label="Preferences..." moonworld="true" shortcut="control|P"> <on_click function="ShowFloater" userdata="preferences" /> @@ -283,9 +284,9 @@ <!-- VIEW --> - <menu name="View" create_jump_keys="true" label="View" + <menu name="View" create_jump_keys="true" label="View" moonworld="true" opaque="true" tear_off="true"> - <menu_item_call name="Mouselook" label="Mouselook" + <menu_item_call name="Mouselook" label="Mouselook" moonworld="true" shortcut="M"> <on_click function="View.Mouselook" userdata="" /> <on_enable function="View.EnableMouselook" /> @@ -301,7 +302,7 @@ <on_check function="View.CheckJoystickFlycam" /> <on_enable function="View.EnableJoystickFlycam" /> </menu_item_check> - <menu_item_call name="Reset View" label="Reset View" + <menu_item_call name="Reset View" label="Reset View" moonworld="true" shortcut="Esc"> <on_click function="View.ResetView" userdata="" /> </menu_item_call> @@ -311,10 +312,11 @@ <on_enable function="View.EnableLastChatter" /> </menu_item_call> <menu_item_separator /> - <menu_item_call name="Web Browser" label="Web Browser" + <menu_item_check name="Web Browser" label="Web Browser" shortcut="control|B"> <on_click function="ShowFloater" userdata="inworld browser" /> - </menu_item_call> + <on_check function="FloaterVisible" userdata="inworld browser" /> + </menu_item_check> <menu_item_separator /> <menu_item_check name="Toolbar" label="Toolbar"> <on_click function="ShowFloater" userdata="toolbar" /> @@ -437,17 +439,17 @@ <on_check function="View.CheckHUDAttachments" /> </menu_item_check> <menu_item_separator /> - <menu name="Zoom Level" create_jump_keys="true" + <menu name="Zoom Level" create_jump_keys="true" moonworld="true" label="Zoom Level" opaque="true" tear_off="true"> - <menu_item_call name="Zoom In" label="Zoom In" + <menu_item_call name="Zoom In" label="Zoom In" moonworld="true" shortcut="control|0"> <on_click function="View.ZoomIn" userdata="" /> </menu_item_call> - <menu_item_call name="Zoom Default" label="Zoom Default" + <menu_item_call name="Zoom Default" label="Zoom Default" moonworld="true" shortcut="control|9"> <on_click function="View.ZoomDefault" userdata="" /> </menu_item_call> - <menu_item_call name="Zoom Out" label="Zoom Out" + <menu_item_call name="Zoom Out" label="Zoom Out" moonworld="true" shortcut="control|8"> <on_click function="View.ZoomOut" userdata="" /> </menu_item_call> @@ -470,7 +472,7 @@ <!-- WORLD --> - <menu name="World" create_jump_keys="true" label="World" + <menu name="World" create_jump_keys="true" label="World" moonworld="true" opaque="true" tear_off="true"> <menu_item_call name="Chat" label="Chat" shortcut=""> <on_click function="World.Chat" userdata="" /> @@ -513,7 +515,7 @@ <on_check function="World.CheckAutoResponse" userdata="" /> </menu_item_check> <menu_item_separator /> - <menu_item_call name="Stop Animating My Avatar" enabled="false" + <menu_item_call name="Stop Animating My Avatar" enabled="false" moonworld="true" label="Stop Animating My Avatar"> <on_click function="Tools.StopAllAnimations" userdata="" /> </menu_item_call> @@ -908,6 +910,15 @@ userdata="notifications" /> </menu_item_call> <menu_item_separator /> + <menu_item_call name="Message Log" label="Message Log"> + <on_click function="Advanced.MessageLog" + userdata="MessageLog" /> + </menu_item_call> + <menu_item_call name="Message Builder" label="Message Builder"> + <on_click function="Advanced.MessageBuilder" + userdata="MessageBuilder" /> + </menu_item_call> + <menu_item_separator /> <menu_item_call name="Region Info to Debug Console" label="Region Info to Debug Console"> <on_click function="Advanced.DumpInfoToConsole" @@ -986,7 +997,8 @@ <on_click function="ShowFloater" userdata="animation list" /> <on_check function="FloaterVisible" userdata="animation list" /> </menu_item_check> - <menu_item_check label="Area Object Search" name="Area Object Search" shortcut="control|shift|A"> + <menu_item_check label="Area Object Search" name="Area Object Search" + shortcut="alt|A"> <on_click function="ShowFloater" userdata="areasearch" /> <on_check function="FloaterVisible" userdata="areasearch" /> </menu_item_check> diff --git a/linden/indra/newview/skins/default/xui/en-us/mime_types_linux.xml b/linden/indra/newview/skins/default/xui/en-us/mime_types_linux.xml new file mode 100755 index 000000000..e95b371d0 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/mime_types_linux.xml @@ -0,0 +1,478 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<mimetypes name="default"> + <defaultlabel> + (Unknown) + </defaultlabel> + <defaultwidget> + none + </defaultwidget> + <defaultimpl> + media_plugin_webkit + </defaultimpl> + <widgetset name="web"> + <label name="web_label"> + Web Content + </label> + <icon> + icn_media_web.tga + </icon> + <default_type> + text/html + </default_type> + <tooltip name="web_tooltip"> + This location has Web content + </tooltip> + <playtip name="web_playtip"> + Show Web content + </playtip> + <allow_resize> + true + </allow_resize> + <allow_looping> + false + </allow_looping> + </widgetset> + <widgetset name="movie"> + <label name="movie_label"> + Movie + </label> + <default_type> + video/* + </default_type> + <icon> + icn_media_movie.tga + </icon> + <tooltip name="movie_tooltip"> + There is a movie to play here + </tooltip> + <playtip name="movie_playtip"> + Play movie + </playtip> + <allow_resize> + false + </allow_resize> + <allow_looping> + true + </allow_looping> + </widgetset> + <widgetset name="image"> + <label name="image_label"> + Image + </label> + <icon> + icn_media_web.tga + </icon> + <default_type> + image/* + </default_type> + <tooltip name="image_tooltip"> + There is an image at this location + </tooltip> + <playtip name="image_playtip"> + View this location's image + </playtip> + <allow_resize> + false + </allow_resize> + <allow_looping> + false + </allow_looping> + </widgetset> + <widgetset name="audio"> + <label name="audio_label"> + Audio + </label> + <icon> + icn_media_web.tga + </icon> + <default_type> + audio/* + </default_type> + <tooltip name="audio_tooltip"> + There is audio at this location + </tooltip> + <playtip name="audio_playtip"> + Play this location's audio + </playtip> + <allow_resize> + false + </allow_resize> + <allow_looping> + true + </allow_looping> + </widgetset> + <scheme name="rtsp"> + <label name="rtsp_label"> + Real Time Streaming + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </scheme> + <mimetype name="blank"> + <label name="blank_label"> + - None - + </label> + <widgettype> + none + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="none/none"> + <label name="none/none_label"> + - None - + </label> + <widgettype> + none + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="audio/*"> + <label name="audio2_label"> + Audio + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype name="video/*"> + <label name="video2_label"> + Video + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype name="image/*"> + <label name="image2_label"> + Image + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="video/vnd.secondlife.qt.legacy"> + <label name="vnd.secondlife.qt.legacy_label"> + Movie (QuickTime) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype name="application/javascript"> + <label name="application/javascript_label"> + Javascript + </label> + <widgettype> + web + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/ogg"> + <label name="application/ogg_label"> + Ogg Audio/Video + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype name="application/pdf"> + <label name="application/pdf_label"> + PDF Document + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/postscript"> + <label name="application/postscript_label"> + Postscript Document + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/rtf"> + <label name="application/rtf_label"> + Rich Text (RTF) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/smil"> + <label name="application/smil_label"> + Synchronized Multimedia Integration Language (SMIL) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/xhtml+xml"> + <label name="application/xhtml+xml_label"> + Web Page (XHTML) + </label> + <widgettype> + web + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/x-director"> + <label name="application/x-director_label"> + Macromedia Director + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="audio/mid"> + <label name="audio/mid_label"> + Audio (MIDI) + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype name="audio/mpeg"> + <label name="audio/mpeg_label"> + Audio (MP3) + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype name="audio/x-aiff"> + <label name="audio/x-aiff_label"> + Audio (AIFF) + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype name="audio/x-wav"> + <label name="audio/x-wav_label"> + Audio (WAV) + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype menu="1" name="image/bmp"> + <label name="image/bmp_label"> + Image (BMP) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="image/gif"> + <label name="image/gif_label"> + Image (GIF) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="image/jpeg"> + <label name="image/jpeg_label"> + Image (JPEG) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="image/png"> + <label name="image/png_label"> + Image (PNG) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="image/svg+xml"> + <label name="image/svg+xml_label"> + Image (SVG) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="image/tiff"> + <label name="image/tiff_label"> + Image (TIFF) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="text/html"> + <label name="text/html_label"> + Web Page + </label> + <widgettype> + web + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="text/plain"> + <label name="text/plain_label"> + Text + </label> + <widgettype> + text + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="text/xml"> + <label name="text/xml_label"> + XML + </label> + <widgettype> + text + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="video/mpeg"> + <label name="video/mpeg_label"> + Movie (MPEG) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype name="video/mp4"> + <label name="video/mp4_label"> + Movie (MP4) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype menu="1" name="video/quicktime"> + <label name="video/quicktime_label"> + Movie (QuickTime) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype name="video/x-ms-asf"> + <label name="video/x-ms-asf_label"> + Movie (Windows Media ASF) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype name="video/x-ms-wmv"> + <label name="video/x-ms-wmv_label"> + Movie (Windows Media WMV) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> + <mimetype menu="1" name="video/x-msvideo"> + <label name="video/x-msvideo_label"> + Movie (AVI) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_gstreamer + </impl> + </mimetype> +</mimetypes> diff --git a/linden/indra/newview/skins/default/xui/en-us/mime_types_mac.xml b/linden/indra/newview/skins/default/xui/en-us/mime_types_mac.xml new file mode 100755 index 000000000..7931e55c0 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/mime_types_mac.xml @@ -0,0 +1,478 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<mimetypes name="default"> + <defaultlabel> + (Unknown) + </defaultlabel> + <defaultwidget> + none + </defaultwidget> + <defaultimpl> + media_plugin_webkit + </defaultimpl> + <widgetset name="web"> + <label name="web_label"> + Web Content + </label> + <icon> + icn_media_web.tga + </icon> + <default_type> + text/html + </default_type> + <tooltip name="web_tooltip"> + This location has Web content + </tooltip> + <playtip name="web_playtip"> + Show Web content + </playtip> + <allow_resize> + true + </allow_resize> + <allow_looping> + false + </allow_looping> + </widgetset> + <widgetset name="movie"> + <label name="movie_label"> + Movie + </label> + <default_type> + video/* + </default_type> + <icon> + icn_media_movie.tga + </icon> + <tooltip name="movie_tooltip"> + There is a movie to play here + </tooltip> + <playtip name="movie_playtip"> + Play movie + </playtip> + <allow_resize> + false + </allow_resize> + <allow_looping> + true + </allow_looping> + </widgetset> + <widgetset name="image"> + <label name="image_label"> + Image + </label> + <icon> + icn_media_web.tga + </icon> + <default_type> + image/* + </default_type> + <tooltip name="image_tooltip"> + There is an image at this location + </tooltip> + <playtip name="image_playtip"> + View this location's image + </playtip> + <allow_resize> + false + </allow_resize> + <allow_looping> + false + </allow_looping> + </widgetset> + <widgetset name="audio"> + <label name="audio_label"> + Audio + </label> + <icon> + icn_media_web.tga + </icon> + <default_type> + audio/* + </default_type> + <tooltip name="audio_tooltip"> + There is audio at this location + </tooltip> + <playtip name="audio_playtip"> + Play this location's audio + </playtip> + <allow_resize> + false + </allow_resize> + <allow_looping> + true + </allow_looping> + </widgetset> + <scheme name="rtsp"> + <label name="rtsp_label"> + Real Time Streaming + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </scheme> + <mimetype name="blank"> + <label name="blank_label"> + - None - + </label> + <widgettype> + none + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype name="none/none"> + <label name="none/none_label"> + - None - + </label> + <widgettype> + none + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="audio/*"> + <label name="audio2_label"> + Audio + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype name="video/*"> + <label name="video2_label"> + Video + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype name="image/*"> + <label name="image2_label"> + Image + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="video/vnd.secondlife.qt.legacy"> + <label name="vnd.secondlife.qt.legacy_label"> + Movie (QuickTime) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype name="application/javascript"> + <label name="application/javascript_label"> + Javascript + </label> + <widgettype> + web + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/ogg"> + <label name="application/ogg_label"> + Ogg Audio/Video + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype name="application/pdf"> + <label name="application/pdf_label"> + PDF Document + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/postscript"> + <label name="application/postscript_label"> + Postscript Document + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/rtf"> + <label name="application/rtf_label"> + Rich Text (RTF) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/smil"> + <label name="application/smil_label"> + Synchronized Multimedia Integration Language (SMIL) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/xhtml+xml"> + <label name="application/xhtml+xml_label"> + Web Page (XHTML) + </label> + <widgettype> + web + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="application/x-director"> + <label name="application/x-director_label"> + Macromedia Director + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="audio/mid"> + <label name="audio/mid_label"> + Audio (MIDI) + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype name="audio/mpeg"> + <label name="audio/mpeg_label"> + Audio (MP3) + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype name="audio/x-aiff"> + <label name="audio/x-aiff_label"> + Audio (AIFF) + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype name="audio/x-wav"> + <label name="audio/x-wav_label"> + Audio (WAV) + </label> + <widgettype> + audio + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype menu="1" name="image/bmp"> + <label name="image/bmp_label"> + Image (BMP) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="image/gif"> + <label name="image/gif_label"> + Image (GIF) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="image/jpeg"> + <label name="image/jpeg_label"> + Image (JPEG) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="image/png"> + <label name="image/png_label"> + Image (PNG) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="image/svg+xml"> + <label name="image/svg+xml_label"> + Image (SVG) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="image/tiff"> + <label name="image/tiff_label"> + Image (TIFF) + </label> + <widgettype> + image + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="text/html"> + <label name="text/html_label"> + Web Page + </label> + <widgettype> + web + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="text/plain"> + <label name="text/plain_label"> + Text + </label> + <widgettype> + text + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype name="text/xml"> + <label name="text/xml_label"> + XML + </label> + <widgettype> + text + </widgettype> + <impl> + media_plugin_webkit + </impl> + </mimetype> + <mimetype menu="1" name="video/mpeg"> + <label name="video/mpeg_label"> + Movie (MPEG) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype name="video/mp4"> + <label name="video/mp4_label"> + Movie (MP4) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype menu="1" name="video/quicktime"> + <label name="video/quicktime_label"> + Movie (QuickTime) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype name="video/x-ms-asf"> + <label name="video/x-ms-asf_label"> + Movie (Windows Media ASF) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype name="video/x-ms-wmv"> + <label name="video/x-ms-wmv_label"> + Movie (Windows Media WMV) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> + <mimetype menu="1" name="video/x-msvideo"> + <label name="video/x-msvideo_label"> + Movie (AVI) + </label> + <widgettype> + movie + </widgettype> + <impl> + media_plugin_quicktime + </impl> + </mimetype> +</mimetypes> diff --git a/linden/indra/newview/skins/default/xui/en-us/mime_types.xml b/linden/indra/newview/skins/default/xui/en-us/mime_types_windows.xml similarity index 85% rename from linden/indra/newview/skins/default/xui/en-us/mime_types.xml rename to linden/indra/newview/skins/default/xui/en-us/mime_types_windows.xml index e3d102148..61067da06 100644 --- a/linden/indra/newview/skins/default/xui/en-us/mime_types.xml +++ b/linden/indra/newview/skins/default/xui/en-us/mime_types_windows.xml @@ -7,7 +7,7 @@ none </defaultwidget> <defaultimpl> - LLMediaImplLLMozLib + media_plugin_webkit </defaultimpl> <widgetset name="web"> <label name="web_label"> @@ -55,27 +55,6 @@ true </allow_looping> </widgetset> - <widgetset name="none"> - <label name="none_label"> - No Content - </label> - <default_type> - none/none - </default_type> - <icon> - icn_media_web.tga - </icon> - <tooltip name="none_tooltip"> - No media here - </tooltip> - <playtip name="none_playtip" /> - <allow_resize> - false - </allow_resize> - <allow_looping> - false - </allow_looping> - </widgetset> <widgetset name="image"> <label name="image_label"> Image @@ -129,6 +108,9 @@ <widgettype> movie </widgettype> + <impl> + media_plugin_quicktime + </impl> </scheme> <mimetype name="blank"> <label name="blank_label"> @@ -138,7 +120,7 @@ none </widgettype> <impl> - LLMediaImplQuickTime + media_plugin_webkit </impl> </mimetype> <mimetype name="none/none"> @@ -148,6 +130,9 @@ <widgettype> none </widgettype> + <impl> + media_plugin_webkit + </impl> </mimetype> <mimetype name="audio/*"> <label name="audio2_label"> @@ -156,6 +141,9 @@ <widgettype> audio </widgettype> + <impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype name="video/*"> <label name="video2_label"> @@ -164,6 +152,9 @@ <widgettype> movie </widgettype> + <impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype name="image/*"> <label name="image2_label"> @@ -172,6 +163,9 @@ <widgettype> image </widgettype> + <impl> + media_plugin_webkit + </impl> </mimetype> <mimetype menu="1" name="video/vnd.secondlife.qt.legacy"> <label name="vnd.secondlife.qt.legacy_label"> @@ -181,8 +175,8 @@ movie </widgettype> <impl> - LLMediaImplQuickTime - </impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype name="application/javascript"> <label name="application/javascript_label"> @@ -191,6 +185,9 @@ <widgettype> web </widgettype> + <impl> + media_plugin_webkit + </impl> </mimetype> <mimetype name="application/ogg"> <label name="application/ogg_label"> @@ -199,6 +196,9 @@ <widgettype> audio </widgettype> + <impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype name="application/pdf"> <label name="application/pdf_label"> @@ -207,6 +207,9 @@ <widgettype> image </widgettype> + <impl> + media_plugin_webkit + </impl> </mimetype> <mimetype name="application/postscript"> <label name="application/postscript_label"> @@ -215,6 +218,9 @@ <widgettype> image </widgettype> + <impl> + media_plugin_webkit + </impl> </mimetype> <mimetype name="application/rtf"> <label name="application/rtf_label"> @@ -223,6 +229,9 @@ <widgettype> image </widgettype> + <impl> + media_plugin_webkit + </impl> </mimetype> <mimetype name="application/smil"> <label name="application/smil_label"> @@ -231,6 +240,9 @@ <widgettype> movie </widgettype> + <impl> + media_plugin_webkit + </impl> </mimetype> <mimetype name="application/xhtml+xml"> <label name="application/xhtml+xml_label"> @@ -239,6 +251,9 @@ <widgettype> web </widgettype> + <impl> + media_plugin_webkit + </impl> </mimetype> <mimetype name="application/x-director"> <label name="application/x-director_label"> @@ -247,14 +262,9 @@ <widgettype> image </widgettype> - </mimetype> - <mimetype name="application/x-shockwave-flash"> - <label name="application/x-shockwave-flash_label"> - Flash - </label> - <widgettype> - image - </widgettype> + <impl> + media_plugin_webkit + </impl> </mimetype> <mimetype name="audio/mid"> <label name="audio/mid_label"> @@ -263,6 +273,9 @@ <widgettype> audio </widgettype> + <impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype name="audio/mpeg"> <label name="audio/mpeg_label"> @@ -271,6 +284,9 @@ <widgettype> audio </widgettype> + <impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype name="audio/x-aiff"> <label name="audio/x-aiff_label"> @@ -279,6 +295,9 @@ <widgettype> audio </widgettype> + <impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype name="audio/x-wav"> <label name="audio/x-wav_label"> @@ -287,6 +306,9 @@ <widgettype> audio </widgettype> + <impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype menu="1" name="image/bmp"> <label name="image/bmp_label"> @@ -296,7 +318,7 @@ image </widgettype> <impl> - LLMediaImplLLMozLib + media_plugin_webkit </impl> </mimetype> <mimetype menu="1" name="image/gif"> @@ -307,7 +329,7 @@ image </widgettype> <impl> - LLMediaImplLLMozLib + media_plugin_webkit </impl> </mimetype> <mimetype menu="1" name="image/jpeg"> @@ -318,7 +340,7 @@ image </widgettype> <impl> - LLMediaImplLLMozLib + media_plugin_webkit </impl> </mimetype> <mimetype menu="1" name="image/png"> @@ -329,7 +351,7 @@ image </widgettype> <impl> - LLMediaImplLLMozLib + media_plugin_webkit </impl> </mimetype> <mimetype name="image/svg+xml"> @@ -340,7 +362,7 @@ image </widgettype> <impl> - LLMediaImplLLMozLib + media_plugin_webkit </impl> </mimetype> <mimetype menu="1" name="image/tiff"> @@ -351,7 +373,7 @@ image </widgettype> <impl> - LLMediaImplLLMozLib + media_plugin_webkit </impl> </mimetype> <mimetype menu="1" name="text/html"> @@ -362,8 +384,8 @@ web </widgettype> <impl> - LLMediaImplLLMozLib - </impl> + media_plugin_webkit + </impl> </mimetype> <mimetype menu="1" name="text/plain"> <label name="text/plain_label"> @@ -373,7 +395,7 @@ text </widgettype> <impl> - LLMediaImplLLMozLib + media_plugin_webkit </impl> </mimetype> <mimetype name="text/xml"> @@ -384,7 +406,7 @@ text </widgettype> <impl> - LLMediaImplLLMozLib + media_plugin_webkit </impl> </mimetype> <mimetype menu="1" name="video/mpeg"> @@ -395,8 +417,8 @@ movie </widgettype> <impl> - LLMediaImplQuickTime - </impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype name="video/mp4"> <label name="video/mp4_label"> @@ -406,8 +428,8 @@ movie </widgettype> <impl> - LLMediaImplQuickTime - </impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype menu="1" name="video/quicktime"> <label name="video/quicktime_label"> @@ -417,8 +439,8 @@ movie </widgettype> <impl> - LLMediaImplQuickTime - </impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype name="video/x-ms-asf"> <label name="video/x-ms-asf_label"> @@ -428,8 +450,8 @@ movie </widgettype> <impl> - LLMediaImplQuickTime - </impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype name="video/x-ms-wmv"> <label name="video/x-ms-wmv_label"> @@ -439,8 +461,8 @@ movie </widgettype> <impl> - LLMediaImplQuickTime - </impl> + media_plugin_quicktime + </impl> </mimetype> <mimetype menu="1" name="video/x-msvideo"> <label name="video/x-msvideo_label"> @@ -450,7 +472,7 @@ movie </widgettype> <impl> - LLMediaImplQuickTime - </impl> + media_plugin_quicktime + </impl> </mimetype> </mimetypes> diff --git a/linden/indra/newview/skins/default/xui/en-us/notifications.xml b/linden/indra/newview/skins/default/xui/en-us/notifications.xml index c69e792d4..b8f3fcbfb 100644 --- a/linden/indra/newview/skins/default/xui/en-us/notifications.xml +++ b/linden/indra/newview/skins/default/xui/en-us/notifications.xml @@ -902,32 +902,32 @@ Would you like to disable all popups which can be skipped? </notification> <notification - icon="alertmodal.tga" + icon="notify.tga" name="CacheWillClear" - type="alertmodal"> + type="notify"> Cache will be cleared after you restart [VIEWER_NAME]. </notification> <notification - icon="alertmodal.tga" + icon="notify.tga" name="CacheWillBeMoved" - type="alertmodal"> + type="notify"> Cache will be moved after you restart [VIEWER_NAME]. Note: This will clear the cache. </notification> <notification - icon="alertmodal.tga" + icon="notify.tga" name="ChangeConnectionPort" - type="alertmodal"> + type="notify"> Port settings take effect after you restart [VIEWER_NAME]. </notification> <notification - icon="alertmodal.tga" + icon="notify.tga" name="ChangeSkin" - type="alertmodal"> + type="notify"> The new skin will appear after you restart [VIEWER_NAME]. </notification> @@ -3651,6 +3651,16 @@ If this box is checked, land owners will not be able to terraform their land reg Default: off </notification> +<notification + icon="alertmodal.tga" + label="Minimum Age" + name="HelpRegionMinimumAge" + type="alertmodal"> +This sets the minimum age (in days) that users entering this sim have to be to enter. + +Default: 0 (disabled) +</notification> + <notification icon="alertmodal.tga" label="Block Fly" @@ -3661,6 +3671,90 @@ If this box is checked, people will not be able to fly in this region regardless Default: off </notification> +<notification + icon="alertmodal.tga" + label="Force Draw Distance" + name="HelpForceDrawDistance" + type="alertmodal"> +If this box is checked, draw distance will be locked for all people in the sim. Note: This will lag people on older machines. PLEASE think before setting this setting. + +Default: off +</notification> + +<notification + icon="alertmodal.tga" + label="Max Inventory Items To Transfer" + name="HelpMaxInventoryItemsTransfer" + type="alertmodal"> +This box controls how many objects can be transfered between clients at a time. -1 sets no limit on the amount of objects. Default Second Life setting is 42. + +Default: -1 +</notification> +<notification + icon="alertmodal.tga" + label="Max Groups" + name="HelpMaxGroups" + type="alertmodal"> +This box controls how many groups an agent can join. -1 sets no limit on the amount of groups. + +Default: -1 +</notification> + <notification + icon="alertmodal.tga" + label="Render Water" + name="HelpRenderWater" + type="alertmodal"> + If this box is checked, water will not be shown for users in this sim. + + Default: -1 + </notification> +<notification + icon="alertmodal.tga" + label="Allow Minimap" + name="HelpAllowMinimap" + type="alertmodal"> +If this box is checked, the minimap will be disabled for users in this sim. + +Default: on +</notification> +<notification + icon="alertmodal.tga" + label="Allow Minimap" + name="HelpAllowPhysicalPrims" + type="alertmodal"> +If this box is checked, physical prims will be allowed to be created in this sim. + +Default: on +</notification> +<notification + icon="alertmodal.tga" + label="Enable Teen Mode" + name="HelpEnableTeenMode" + type="alertmodal"> +If this box is checked, all avatars will be forced to wear underwear and will not be able to take it off. + +Default: off +</notification> +<notification + icon="alertmodal.tga" + label="Show Tags" + name="HelpShowTags" + type="alertmodal"> +This box controls how avatar name tags are shown in this sim. 2 sets tags to always be shown. 1 sets tags to disappear after some time. 0 blocks the viewing of name tags. + +Default: 2 +</notification> +<notification + icon="alertmodal.tga" + label="Allow Parcel WindLight" + name="HelpAllowParcelWindLight" + type="alertmodal"> +If this box is checked, setting WindLight settings in parcels will be enabled. + +Default: on +</notification> + + <notification icon="alertmodal.tga" label="Bulk Change Content Permissions" @@ -5556,7 +5650,25 @@ Apple's QuickTime software does not appear to be installed on your system. If you want to view streaming media on parcels that support it you should go to the QuickTime site (http://www.apple.com/quicktime) and install the QuickTime Player. </notification> +<notification + icon="notify.tga" + name="NoPlugin" + type="notify"> +No Media Plugin was found to handle the "[MIME_TYPE]" mime type. Media of this type will be unavailable. +</notification> +<notification + icon="alertmodal.tga" + name="MediaPluginFailed" + type="alertmodal"> +The following Media Plugin has failed: +[PLUGIN] +Please re-install the plugin or contact the vendor if you continue to experience problems. + <form name="form"> + <ignore name="ignore" + text="When a Media Plugin fails"/> + </form> +</notification> <notification icon="notify.tga" name="OwnedObjectsReturned" @@ -7104,8 +7216,8 @@ Apply this region's settings? ("Ignore" will ignore all region setting <notification name="ChangeFont" - icon="alertmodal.tga" - type="alertmodal"> + icon="notify.tga" + type="notify"> The new font will appear after you restart [VIEWER_NAME]. </notification> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_avatar.xml b/linden/indra/newview/skins/default/xui/en-us/panel_avatar.xml index 2360e6b36..0df65e799 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_avatar.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_avatar.xml @@ -138,11 +138,11 @@ bottom_delta="-6" drop_shadow_visible="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="16" left_delta="0" mouse_opaque="true" name="About:" v_pad="0" width="170"> - About (500 chars): + About (8196 chars): </text> <text_editor bottom_delta="-137" embedded_items="false" enabled="true" follows="left|top" font="SansSerifSmall" height="137" - is_unicode="false" left_delta="0" max_length="511" mouse_opaque="true" + is_unicode="false" left_delta="0" max_length="8196" mouse_opaque="true" name="about" width="235" word_wrap="true" spell_check="true" /> <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" @@ -350,11 +350,11 @@ bottom_delta="-8" drop_shadow_visible="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="16" left="12" mouse_opaque="true" name="Info:" v_pad="0" width="161"> - Info (250 chars): + Info (8196 chars): </text> <text_editor bottom_delta="-179" embedded_items="false" enabled="true" follows="left|top" font="SansSerifSmall" height="178" - is_unicode="false" left="12" max_length="254" mouse_opaque="false" + is_unicode="false" left="12" max_length="8196" mouse_opaque="false" name="about" width="378" word_wrap="true" spell_check="true" /> </panel> <panel border="true" bottom="-482" follows="left|top|right|bottom" height="466" @@ -372,7 +372,7 @@ </text> <text_editor bottom_delta="-260" embedded_items="false" enabled="true" follows="left|top" font="SansSerif" height="256" is_unicode="false" left="10" - max_length="1023" mouse_opaque="true" name="notes edit" width="400" + max_length="8196" mouse_opaque="true" name="notes edit" width="400" word_wrap="false" spell_check="true" /> </panel> </tab_container> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_bars.xml b/linden/indra/newview/skins/default/xui/en-us/panel_bars.xml index 4a13604bb..aab98db36 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_bars.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_bars.xml @@ -15,7 +15,4 @@ <layout_panel auto_resize="false" filename="panel_toolbar.xml" name="toolbar" use_bounding_rect="true" user_resize="false" width="1024" min_height="28" /> </layout_stack> - <panel auto_resize="true" background_visible="false" bottom="50" - follows="left|right|top|bottom" height="728" left="0" mouse_opaque="false" - name="hud" user_resize="false" width="1024" /> </panel> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_hud.xml b/linden/indra/newview/skins/default/xui/en-us/panel_hud.xml new file mode 100644 index 000000000..95f828996 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/panel_hud.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel border="false" auto_resize="true" background_visible="false" bottom="50" + follows="left|right|top|bottom" height="728" left="0" mouse_opaque="false" + name="hud" user_resize="false" width="1024" /> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_login.xml b/linden/indra/newview/skins/default/xui/en-us/panel_login.xml index 96f3f7718..048005d91 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_login.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_login.xml @@ -1,13 +1,27 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel name="panel_login" - bottom="0" left="0" height="600" width="800" - follows="left|top|right|bottom" mouse_opaque="true" > - - <web_browser name="login_html" - bottom="0" top="-1" left="0" right="-1" - border_visible="false" follows="top|left|bottom|right" - start_url="data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody bgcolor=%22#000000%22 text=%22ffffff%22%3E%3Ch1%3E%3Ctt%3Eloading...%3C/tt%3E%3C/h1%3E %3C/body%3E %3C/html%3E" /> + bottom="0" left="0" height="600" width="800" + follows="left|top|right|bottom" mouse_opaque="true" > + + <web_browser name="login_html" + bottom="0" top="-1" left="0" right="-1" + border_visible="false" follows="top|left|bottom|right" + start_url="data:text/html, + %3Chtml%3E + %3Chead%3E %3C/head%3E + %3Cbody bgcolor=%22#5a2d65%22 text=%22ffffff%22%3E + %3Ctable width=%22100%%22 height=%22100%%22 border=%220%22%3E + %3Ctr%3E + %3Ctd align=%22center%22 valign=%22middle%22 style=%22font-size:0.8em;%22%3E + %3Cimg src=%22imprudence_loading.png%22 align=%22absmiddle%22%3E + %3Cbr/%3E + %3CH1%3Eloading...%3C/H1%3E + %3C/td%3E + %3C/tr%3C + %3C/table%3E + %3C/body%3E + %3C/html%3E" /> <string name="real_url"> http://secondlife.com/app/login/ </string> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_media_hud.xml b/linden/indra/newview/skins/default/xui/en-us/panel_media_hud.xml new file mode 100644 index 000000000..1c0781a5b --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/panel_media_hud.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel border="false" follows="" height="160" visible="false" mouse_opaque="false" + label="" name="MediaHUD" width="208" background_visible="false" background_opaque="false" bg_alpha_color="1 1 1 0.0"> +<panel name="media_region" left="20" right="-20" bottom="35" top="-20" follows="left|right|top|bottom" visible="true" background_opaque="false" + mouse_opaque="false"/> + <!--icon name="bg_image" image_name="media_panel_hoverrectangle.png" visible="true" left="10" bottom="32" right="-10" top="-10" follows="left|right|top|bottom"/--> + <layout_stack orientation="horizontal" left="0" bottom="0" follows="left|right|bottom" visible="true" width="208" height="32"> + <layout_panel user_resize="false"/> + <layout_panel user_resize="false" auto_resize="false" width="210" min_width="208"> + <panel name="media_focused_controls" width="208" left="0" height="32" bottom="0" visible="true"> + <icon name="media_panel_transportcontrols_bg" image_name="media_panel_bg.png" visible="true" height="32" width="99" scale_image="true" bottom="0"/> + <button name="back" label="" left="4" width="20" bottom="6" height="22" image_unselected="media_btn_back.png" + image_selected="media_btn_back.png" scale_image="true"/> + <icon name="media_panel_divider-1" image_name="media_panel_divider.png" visible="true" height="22" width="3" left_delta="20" + scale_image="false" bottom="5"/> + <button name="fwd" label="" left_delta="3" width="17" bottom_delta="0" height="22" image_unselected="media_btn_forward.png" + image_selected="media_btn_forward.png" scale_image="true"/> + <icon name="media_panel_divider-2" image_name="media_panel_divider.png" visible="true" height="22" width="3" left_delta="17" + scale_image="false" bottom="5"/> + <button name="home" label="" left_delta="3" width="22" bottom_delta="0" height="22" image_unselected="media_btn_home.png" + image_selected="media_btn_home.png" scale_image="true"/> + <button name="media_stop" label="" left_delta="0" width="22" bottom_delta="0" height="22" image_unselected="button_anim_stop.tga" + image_selected="button_anim_stop.tga" scale_image="true"/> + <icon name="media_panel_divider-3" image_name="media_panel_divider.png" visible="true" height="22" width="3" left_delta="22" + scale_image="false" bottom="5"/> + <button name="reload" label="" left_delta="3" width="22" bottom_delta="0" height="22" image_unselected="media_btn_reload.png" + image_selected="media_btn_reload.png" scale_image="true"/> + <button name="stop" label="" left_delta="0" width="22" bottom_delta="0" height="22" image_unselected="media_btn_stoploading.png" + image_selected="media_btn_stoploading.png" scale_image="true" visible="false"/> + <button name="play" label="" left_delta="0" width="22" bottom_delta="0" height="22" image_unselected="button_anim_play.tga" + image_selected="button_anim_play.tga" scale_image="true" visible="false"/> + <button name="pause" label="" left_delta="0" width="22" bottom_delta="0" height="22" image_unselected="button_anim_pause.tga" + image_selected="button_anim_pause.tga" scale_image="true" visible="false"/> + <icon name="media_panel_scrollbg" image_name="media_panel_scrollbg.png" visible="true" height="32" width="32" + scale_image="false" bottom="0" left="97"/> + <button name="scrollup" label="" left="109" width="8" bottom="20" height="8" image_unselected="media_btn_scrollup.png" + image_selected="media_btn_scrollup.png" scale_image="false"/> + <button name="scrollleft" label="" left="100" width="8" bottom="12" height="8" image_unselected="media_btn_scrollleft.png" + image_selected="media_btn_scrollleft.png" scale_image="false"/> + <button name="scrollright" label="" left="117" width="8" bottom="12" height="8" image_unselected="media_btn_scrollright.png" + image_selected="media_btn_scrollright.png" scale_image="false"/> + <button name="scrolldown" label="" left="109" width="8" bottom="4" height="8" image_unselected="media_btn_scrolldown.png" + image_selected="media_btn_scrolldown.png" scale_image="false"/> + <icon name="media_panel_metacontrols_bg" image_name="media_panel_bg.png" visible="true" height="32" width="81" + scale_image="true" bottom="0" left="127"/> + <button name="zoom_frame" label="" left_delta="4" width="22" bottom="5" height="22" image_unselected="media_btn_optimalzoom.png" + image_selected="media_btn_optimalzoom.png" scale_image="true"/> + <icon name="media_panel_divider-4" image_name="media_panel_divider.png" visible="true" height="22" width="3" left_delta="22" + scale_image="false" bottom="5"/> + <button name="new_window" label="" left_delta="3" width="24" bottom_delta="1" height="22" image_unselected="media_btn_newwindow.png" + image_selected="media_btn_newwindow.png" scale_image="true"/> + <icon name="media_panel_divider-5" image_name="media_panel_divider.png" visible="true" height="22" width="3" left_delta="24" + scale_image="false" bottom="5"/> + <button name="close" label="" left_delta="3" width="21" bottom_delta="1" height="22" image_unselected="media_btn_done.png" + image_selected="media_btn_done.png" scale_image="true"/> + </panel> + <panel name="media_hover_controls" width="57" left="74" height="32" bottom="0" visible="false"> + <icon name="media_panel_metacontrols_bg-hover" image_name="media_panel_bg.png" visible="true" height="32" width="57" scale_image="true" bottom="0" left="0"/> + <button name="zoom_frame_hover" label="" left_delta="4" width="22" bottom="5" height="22" image_unselected="media_btn_optimalzoom.png" image_selected="media_btn_optimalzoom.png" + scale_image="true"/> + <icon name="media_panel_divider" image_name="media_panel_divider.png" visible="true" height="22" width="3" left_delta="22" scale_image="false" bottom="5"/> + <button name="new_window_hover" label="" left_delta="3" width="24" bottom_delta="1" height="22" image_unselected="media_btn_newwindow.png" image_selected="media_btn_newwindow.png" + scale_image="true"/> + </panel> + </layout_panel> + <layout_panel user_resize="false"/> + </layout_stack> +</panel> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_advanced.xml b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_advanced.xml index 0f2181bab..eeaf094d9 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_advanced.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_advanced.xml @@ -38,11 +38,11 @@ font="SansSerifSmall" height="16" initial_value="false" label="Enable shadows (WARNING: unstable and requires Ultra graphics)" left="12" mouse_opaque="true" name="shadows_check" radio_style="false" width="217" /> - <text bottom_delta="-25" left="16" height="15" width="300" + <text bottom_delta="-25" left="16" height="15" width="300" moonworld="false" follows="top|left"> Allow region WindLight settings (LightShare): </text> - <combo_box name="lightshare_combo" + <combo_box name="lightshare_combo" moonworld="false" bottom_delta="-2" left_delta="250" height="18" width="135" allow_text_entry="false" follows="left|top"> <combo_item type="string" name="never" value="0"> @@ -179,57 +179,6 @@ To use spellcheck, right-click a misspelled word tool_tip="Modify the AutoCorrect word list and settings" left="12" bottom_delta="-50" width="180" height="20" font="SansSerifSmall" follows="left|top"/> </panel> - - <panel border="true" bottom="-580" follows="left|top|right|bottom" height="525" label="Extra" - left="1" mouse_opaque="true" name="Extra" width="418"> - - <check_box bottom_delta="-30" enabled="true" follows="left|top" font="SansSerifSmall" height="16" - initial_value="true" label="Show chat messages from friends in a different color" left="12" - mouse_opaque="true" name="HighlightFriendsChat" radio_style="false" width="270"/> - - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-100" - can_apply_immediately="true" color="1 1 1 1" control_name="FriendsChatColor" - enabled="true" follows="left|top" height="67" label="Friends" left_delta="68" - mouse_opaque="true" name="FriendsChatColor" width="65" /> - - <check_box bottom_delta="-30" enabled="true" follows="left|top" - font="SansSerifSmall" height="16" initial_value="true" - label="Show chat messages containing your name in a different color" left="12" mouse_opaque="true" - name="HighlightOwnNameInChat" radio_style="false" width="217" /> - - <check_box bottom_delta="-30" enabled="true" follows="left|top" font="SansSerifSmall" height="16" - initial_value="true" label="Show GroupIM messages containing your name in a different color" left="12" - mouse_opaque="true" name="HighlightOwnNameInIM" radio_style="false" width="270"/> - - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-230" - can_apply_immediately="true" color="1 1 1 1" control_name="OwnNameChatColor" - enabled="true" follows="left|top" height="67" label="Own Name" left_delta="68" - mouse_opaque="true" name="OwnNameChatColor" width="65" /> - - <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="-50" - enabled="true" follows="left|top" font="SansSerif" - handle_edit_keys_directly="true" height="20" left_delta="0" - max_length="50" mouse_opaque="true" name="nick01" - select_all_on_focus_received="true" width="400" word_wrap="false" /> - <text bottom_delta="-3" follows="left|top" font="SansSerifSmall" height="20" left="20" name="nick01_text" width="70">Nick 1</text> - - <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="-30" - enabled="true" follows="left|top" font="SansSerif" - handle_edit_keys_directly="true" height="20" left_delta="60" - max_length="50" mouse_opaque="true" name="nick02" - select_all_on_focus_received="true" width="400" word_wrap="false" /> - - <text bottom_delta="-3" follows="left|top" font="SansSerifSmall" height="20" left="20" name="nick02_text" width="70">Nick 2</text> - - <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="-30" - enabled="true" follows="left|top" font="SansSerif" - handle_edit_keys_directly="true" height="20" left_delta="60" - max_length="50" mouse_opaque="true" name="nick03" - select_all_on_focus_received="true" width="400" word_wrap="false" /> - - <text bottom_delta="-3" follows="left|top" font="SansSerifSmall" height="20" left="20" name="nick03_text" width="70">Nick 3</text> - - </panel> </tab_container> </panel> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_chat.xml b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_chat.xml index 95d0c33dd..9ead3bf45 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_chat.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_chat.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel border="true" bottom="-409" enabled="true" follows="left|top|right|bottom" - height="408" label="Text Chat" left="102" mouse_opaque="true" name="chat" + height="408" label="Chat" left="102" mouse_opaque="true" name="chat" width="517"> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" bottom="-20" drop_shadow_visible="true" enabled="true" follows="left|top" @@ -24,60 +24,84 @@ Large </radio_item> </radio_group> + + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom_delta="-40" drop_shadow_visible="true" enabled="true" follows="left|top" + font="SansSerifSmall" h_pad="0" halign="left" height="10" left="12" + mouse_opaque="false" name="text_translate_chat" v_pad="0" width="128"> + Translate Chat: + </text> + <check_box bottom_delta="-3" control_name="TranslateChat" enabled="true" follows="left|top" + font="SansSerifSmall" height="16" initial_value="false" + label="Use machine translation while chatting (powered by Google)" left="148" mouse_opaque="true" + name="translate_chat" radio_style="false" width="237" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom_delta="-16" drop_shadow_visible="true" enabled="true" follows="left|top" + font="SansSerifSmall" h_pad="0" halign="left" height="10" left="149" + mouse_opaque="false" name="text_translate_chat" v_pad="0" width="160"> + Translate into this language: + </text> + <combo_box allow_text_entry="true" bottom_delta="-5" enabled="true" + follows="left|top" height="16" left_delta="183" max_chars="135" + mouse_opaque="true" name="translate_language_combobox" width="146"> + <combo_item type="string" length="1" enabled="true" name="System Default Language" value="default"> + System Default + </combo_item> + <combo_item type="string" length="1" enabled="true" name="English" value="en"> + English + </combo_item> + + <!-- After "System Default" and "English", please keep the rest of these combo_items in alphabetical order by the first character in the string. --> + + <combo_item type="string" length="1" enabled="true" name="Danish" value="da"> + Dansk (Danish) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Deutsch(German)" value="de"> + Deutsch (German) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Spanish" value="es"> + Español (Spanish) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="French" value="fr"> + Français (French) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Italian" value="it"> + Italiano (Italian) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Hungarian" value="hu"> + Magyar (Hungarian) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Dutch" value="nl"> + Nederlands (Dutch) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Polish" value="pl"> + Polski (Polish) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Portugese" value="pt"> + Portugués (Portuguese) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Russian" value="ru"> + Русский (Russian) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Turkish" value="tr"> + Türkçe (Turkish) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Ukrainian" value="uk"> + Українська (Ukrainian) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Chinese" value="zh"> + 中文 (简体) (Chinese) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="(Japanese)" value="ja"> + 日本語 (Japanese) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="(Korean)" value="ko"> + 한국어 (Korean) + </combo_item> + </combo_box> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-64" drop_shadow_visible="true" enabled="true" follows="left|top" - font="SansSerifSmall" h_pad="0" halign="left" height="10" left="12" - mouse_opaque="false" name="text_box2" v_pad="0" width="128"> - Color: - </text> - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-108" - can_apply_immediately="true" color="1 1 1 1" control_name="UserChatColor" - enabled="true" follows="left|top" height="56" label="You" left="148" - mouse_opaque="true" name="user" width="54" /> - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-108" - can_apply_immediately="true" color="1 1 1 1" control_name="AgentChatColor" - enabled="true" follows="left|top" height="56" label="Others" left_delta="68" - mouse_opaque="true" name="agent" width="54" /> - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-108" - can_apply_immediately="true" color="0.6 0.6 1 1" - enabled="true" follows="left|top" height="56" label="IMs" left_delta="68" - mouse_opaque="true" name="im" width="54" /> - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-108" - can_apply_immediately="true" color="0.8 1 1 1" - enabled="true" follows="left|top" - height="56" label="System" left_delta="68" mouse_opaque="true" - name="system" width="54" /> - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-108" - can_apply_immediately="true" color="0.82 0.82 0.99 1" - control_name="ScriptErrorColor" enabled="true" follows="left|top" - height="56" label="Errors" left_delta="68" mouse_opaque="true" - name="script_error" width="54" /> - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-165" - can_apply_immediately="true" color="0.7 0.9 0.7 1" - control_name="ObjectChatColor" enabled="true" follows="left|top" - height="56" label="Objects" left="148" mouse_opaque="true" - name="objects" width="54" /> - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-165" - can_apply_immediately="true" color="0.7 0.9 0.7 1" - control_name="ObjectIMColor" enabled="true" follows="left|top" - height="56" label="Object IMs" left_delta="68" mouse_opaque="true" - name="object_ims" width="54" /> - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-165" - can_apply_immediately="true" color="0.7 0.9 0.7 1" - enabled="true" follows="left|top" - height="56" label="Owner" left_delta="68" mouse_opaque="true" name="owner" - width="54" /> - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-165" - can_apply_immediately="true" color="0 0 0 1" - enabled="true" follows="left|top" - height="56" label="Bubble" left_delta="68" mouse_opaque="true" - name="background" width="54" /> - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-165" - can_apply_immediately="true" color="0.6 0.6 1 1" - enabled="true" follows="left|top" height="56" - label="URLs" left_delta="68" mouse_opaque="true" name="links" width="54" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom_delta="-25" drop_shadow_visible="true" enabled="true" follows="left|top" + bottom_delta="-40" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="10" left="12" mouse_opaque="false" name="text_box3" v_pad="0" width="135"> Chat Console: @@ -115,8 +139,29 @@ label="Use full screen width (requires restart)" left="148" mouse_opaque="true" name="chat_full_width_check" radio_style="false" width="239" /> + + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom_delta="-40" drop_shadow_visible="true" enabled="true" follows="left|top" + font="SansSerifSmall" h_pad="0" halign="left" height="10" left="12" + mouse_opaque="false" name="text_box7" v_pad="0" width="128"> + Chat Bubbles: + </text> + <check_box bottom_delta="-8" control_name="UseChatBubbles" enabled="true" follows="left|top" + font="SansSerifSmall" height="16" initial_value="false" + label="Show chat bubbles" left="148" mouse_opaque="true" + name="bubble_text_chat" radio_style="false" width="237" /> + <check_box bottom_delta="-0" control_name="UseLocalChatBubbles" enabled="true" follows="left|top" + font="SansSerifSmall" height="16" initial_value="false" + label="Show local chat and bubbles" left="288" mouse_opaque="true" + name="local_bubble_text_chat" radio_style="false" width="237" /> + <slider bottom_delta="-20" can_edit_text="false" control_name="ChatBubbleOpacity" + decimal_digits="3" enabled="true" follows="left|top" height="12" + increment="0.05" initial_val="1" label="Bubble opacity:" left="148" max_val="1" + min_val="0" mouse_opaque="true" name="bubble_chat_opacity" show_text="true" + value="0.5" width="225" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom_delta="-20" drop_shadow_visible="true" enabled="true" follows="left|top" + bottom_delta="-40" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="10" left="12" mouse_opaque="false" name="text_box6" v_pad="0" width="135"> Miscellaneous: @@ -147,94 +192,5 @@ font="SansSerifSmall" height="16" initial_value="false" label="Show custom chat channel" left="148" mouse_opaque="true" name="toggle_channel_control" radio_style="false" width="237" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-379" drop_shadow_visible="true" enabled="true" follows="left|top" - font="SansSerifSmall" h_pad="0" halign="left" height="10" left="12" - mouse_opaque="false" name="text_box7" v_pad="0" width="128"> - Chat Bubbles: - </text> - <check_box bottom="-386" control_name="UseChatBubbles" enabled="true" follows="left|top" - font="SansSerifSmall" height="16" initial_value="false" - label="Show chat bubbles" left="148" mouse_opaque="true" - name="bubble_text_chat" radio_style="false" width="237" /> - <slider bottom="-402" can_edit_text="false" control_name="ChatBubbleOpacity" - decimal_digits="3" enabled="true" follows="left|top" height="12" - increment="0.05" initial_val="1" label="Bubble opacity:" left="148" max_val="1" - min_val="0" mouse_opaque="true" name="bubble_chat_opacity" show_text="true" - value="0.5" width="225" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-420" drop_shadow_visible="true" enabled="true" follows="left|top" - font="SansSerifSmall" h_pad="0" halign="left" height="10" left="12" - mouse_opaque="false" name="text_translate_chat" v_pad="0" width="128"> - Translate Chat: - </text> - <check_box bottom="-427" control_name="TranslateChat" enabled="true" follows="left|top" - font="SansSerifSmall" height="16" initial_value="false" - label="Use machine translation while chatting (powered by Google)" left="148" mouse_opaque="true" - name="translate_chat" radio_style="false" width="237" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-442" drop_shadow_visible="true" enabled="true" follows="left|top" - font="SansSerifSmall" h_pad="0" halign="left" height="10" left="149" - mouse_opaque="false" name="text_translate_chat" v_pad="0" width="160"> - Translate into this language: - </text> - <combo_box allow_text_entry="true" bottom="-448" enabled="true" - follows="left|top" height="16" left_delta="183" max_chars="135" - mouse_opaque="true" name="translate_language_combobox" width="146"> - <combo_item type="string" length="1" enabled="true" name="System Default Language" value="default"> - System Default - </combo_item> - <combo_item type="string" length="1" enabled="true" name="English" value="en"> - English - </combo_item> - - <!-- After "System Default" and "English", please keep the rest of these combo_items in alphabetical order by the first character in the string. --> - - <combo_item type="string" length="1" enabled="true" name="Danish" value="da"> - Dansk (Danish) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="Deutsch(German)" value="de"> - Deutsch (German) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="Spanish" value="es"> - Español (Spanish) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="French" value="fr"> - Français (French) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="Italian" value="it"> - Italiano (Italian) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="Hungarian" value="hu"> - Magyar (Hungarian) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="Dutch" value="nl"> - Nederlands (Dutch) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="Polish" value="pl"> - Polski (Polish) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="Portugese" value="pt"> - Portugués (Portuguese) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="Russian" value="ru"> - Русский (Russian) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="Turkish" value="tr"> - Türkçe (Turkish) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="Ukrainian" value="uk"> - Українська (Ukrainian) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="Chinese" value="zh"> - 中文 (简体) (Chinese) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="(Japanese)" value="ja"> - 日本語 (Japanese) - </combo_item> - <combo_item type="string" length="1" enabled="true" name="(Korean)" value="ko"> - 한국어 (Korean) - </combo_item> - </combo_box> </panel> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_colors.xml b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_colors.xml new file mode 100644 index 000000000..40a75a6ca --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_colors.xml @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel border="true" bottom="-409" enabled="true" follows="left|top|right|bottom" + height="408" label="Chat Colors" left="102" mouse_opaque="true" name="colors" + width="517"> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-20" drop_shadow_visible="true" enabled="true" follows="left|top" + font="SansSerifSmall" h_pad="0" halign="left" height="10" left="12" + mouse_opaque="false" name="text_box2" v_pad="0" width="128"> + Chat Colors: + </text> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-75" + can_apply_immediately="true" color="1 1 1 1" control_name="UserChatColor" + enabled="true" follows="left|top" height="65" label="Your chat" left="120" + mouse_opaque="true" name="user" width="65" /> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-75" + can_apply_immediately="true" color="1 1 1 1" control_name="AgentChatColor" + enabled="true" follows="left|top" height="65" label="Others' chat" left_delta="76" + mouse_opaque="true" name="agent" width="65" /> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-75" + can_apply_immediately="true" color="0.6 0.6 1 1" + enabled="true" follows="left|top" height="65" label="IMs" left_delta="76" + mouse_opaque="true" name="im" width="65" /> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-75" + can_apply_immediately="true" color="0.8 1 1 1" + enabled="true" follows="left|top" + height="65" label="System" left_delta="76" mouse_opaque="true" + name="system" width="65" /> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-75" + can_apply_immediately="true" color="0.82 0.82 0.99 1" + control_name="ScriptErrorColor" enabled="true" follows="left|top" + height="65" label="Script errors" left_delta="76" mouse_opaque="true" + name="script_error" width="65" /> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-146" + can_apply_immediately="true" color="0.7 0.9 0.7 1" + control_name="ObjectChatColor" enabled="true" follows="left|top" + height="65" label="Object chat" left="120" mouse_opaque="true" + name="objects" width="65" /> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-146" + can_apply_immediately="true" color="0.7 0.9 0.7 1" + control_name="ObjectIMColor" enabled="true" follows="left|top" + height="65" label="Object IMs" left_delta="76" mouse_opaque="true" + name="object_ims" width="65" /> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-146" + can_apply_immediately="true" color="0.7 0.9 0.7 1" + enabled="true" follows="left|top" + height="65" label="Owner chat" left_delta="76" mouse_opaque="true" name="owner" + width="65" /> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-146" + can_apply_immediately="true" color="0 0 0 1" + enabled="true" follows="left|top" + height="65" label="Bubble chat" left_delta="76" mouse_opaque="true" + name="background" width="65" /> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-146" + can_apply_immediately="true" color="0.6 0.6 1 1" + enabled="true" follows="left|top" height="65" + label="Links" left_delta="76" mouse_opaque="true" name="links" width="65" /> + + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom_delta="-30" drop_shadow_visible="true" enabled="true" follows="left|top" + font="SansSerifSmall" h_pad="0" halign="left" height="10" left="12" + mouse_opaque="false" name="text_box3" v_pad="0" width="128"> + Line Highlighting: + </text> + + <check_box bottom_delta="-7" enabled="true" follows="left|top" font="SansSerifSmall" height="16" + initial_value="true" label="Highlight chat from friends" left="120" + mouse_opaque="true" name="HighlightFriendsChat" radio_style="false" width="270"/> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom_delta="-70" + can_apply_immediately="true" color="1 1 1 1" control_name="FriendsChatColor" + enabled="true" follows="left|top" height="65" label="Friends" left_delta="20" + mouse_opaque="true" name="FriendsChatColor" width="65" /> + + <check_box bottom_delta="-25" enabled="true" follows="left|top" + font="SansSerifSmall" height="16" initial_value="true" + label="Highlight local chat containing your name" left="120" mouse_opaque="true" + name="HighlightOwnNameInChat" radio_style="false" width="217" /> + <check_box bottom_delta="-20" enabled="true" follows="left|top" font="SansSerifSmall" height="16" + initial_value="true" label="Highlight group chat containing your name" left_delta="0" + mouse_opaque="true" name="HighlightOwnNameInIM" radio_style="false" width="270"/> + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom_delta="-70" + can_apply_immediately="true" color="1 1 1 1" control_name="OwnNameChatColor" + enabled="true" follows="left|top" height="65" label="Your name" left_delta="20" + mouse_opaque="true" name="OwnNameChatColor" width="65" /> + + <text bottom_delta="-30" follows="left|top" font="SansSerifSmall" height="20" + left="140" name="nick01_text" width="150"> + Highlight nickname 1: + </text> + <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="3" + enabled="true" follows="left|top" font="SansSerif" + handle_edit_keys_directly="true" height="20" left_delta="125" + max_length="50" mouse_opaque="true" name="nick01" + select_all_on_focus_received="true" width="160" word_wrap="false" /> + + <text bottom_delta="-25" follows="left|top" font="SansSerifSmall" height="20" + left="140" name="nick02_text" width="150"> + Highlight nickname 2: + </text> + <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="3" + enabled="true" follows="left|top" font="SansSerif" + handle_edit_keys_directly="true" height="20" left_delta="125" + max_length="50" mouse_opaque="true" name="nick02" + select_all_on_focus_received="true" width="160" word_wrap="false" /> + + <text bottom_delta="-25" follows="left|top" font="SansSerifSmall" height="20" + left="140" name="nick03_text" width="150"> + Highlight nickname 3: + </text> + <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="3" + enabled="true" follows="left|top" font="SansSerif" + handle_edit_keys_directly="true" height="20" left_delta="125" + max_length="50" mouse_opaque="true" name="nick03" + select_all_on_focus_received="true" width="160" word_wrap="false" /> + +</panel> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_fonts.xml b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_fonts.xml index 5865becf1..c64ce9fad 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_fonts.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_fonts.xml @@ -46,4 +46,14 @@ Preview: The quick brown fox jumped over the lazy dog. :) </text> + + <spinner name="font_mult" label="Font size multiplier:" label_width="130" + bottom="-280" left="20" height="16" width="180" follows="left|top" + decimal_digits="2" increment="0.01" max_val="3.0" min_val="0.1" + tool_tip="Multiply all font sizes by this amount." /> + + <check_box name="font_round" follows="left|top" + bottom="-300" left="20" height="16" width="300" + label="Force integer font sizes (may fix blurry fonts)" /> + </panel> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_general.xml b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_general.xml index f85e3c0a2..4b0b29246 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_general.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_general.xml @@ -17,7 +17,7 @@ </combo_item> </combo_box> <button name="grid_btn" label="Grid Manager" - bottom_delta="0" left="330" height="16" width="100" + bottom_delta="-3" left="330" height="20" width="100" follows="left|top" font="SansSerifSmall" halign="center" mouse_opaque="true" scale_image="TRUE" /> <check_box bottom="-44" enabled="true" follows="left|top" @@ -57,38 +57,38 @@ font="SansSerifSmall" height="16" initial_value="false" label="Hide all group titles" left="151" mouse_opaque="true" name="show_all_title_checkbox" radio_style="false" width="256" /> - <check_box bottom_delta="-18" follows="left|top" + <check_box bottom_delta="0" follows="left|top" font="SansSerifSmall" height="16" initial_value="false" - label="Hide my group title" left="151" name="show_my_title_checkbox" + label="Hide my group title" left="330" name="show_my_title_checkbox" radio_style="false" width="256" /> - <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-230" + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-210" can_apply_immediately="false" color="1 1 1 1" enabled="true" follows="left|top" height="65" label="" left="153" mouse_opaque="true" name="effect_color_swatch" tool_tip="Click to open Color Picker" width="55" /> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-235" drop_shadow_visible="true" enabled="true" follows="left|top" + bottom="-215" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="12" left="10" mouse_opaque="true" name="UI Size:" v_pad="0" width="128"> UI Size: </text> - <slider bottom="-237" can_edit_text="true" + <slider bottom="-217" can_edit_text="true" decimal_digits="3" enabled="true" height="16" increment="0.001" initial_val="1" left="148" max_val="1.4" min_val="0.75" mouse_opaque="true" name="ui_scale_slider" show_text="true" value="1" width="220" /> - <button bottom="-241" enabled="true" follows="left|top" + <button bottom="-221" enabled="true" follows="left|top" font="SansSerif" halign="center" height="22" label="Reset" label_selected="Reset" left_delta="226" mouse_opaque="true" name="reset_ui_size" scale_image="true" width="80" /> - <check_box bottom="-256" enabled="true" follows="left|top" + <check_box bottom="-236" enabled="true" follows="left|top" font="SansSerifSmall" height="16" initial_value="false" label="Use resolution independent scale" left="151" mouse_opaque="true" name="ui_auto_scale" radio_style="false" width="256" /> - <check_box bottom="-280" enabled="true" follows="left|top" + <check_box bottom="-260" enabled="true" follows="left|top" font="SansSerifSmall" height="16" initial_value="false" label="Go Away/AFK when idle" left="330" mouse_opaque="true" name="afk_timeout_checkbox" radio_style="false" width="256" /> - <spinner bottom="-280" decimal_digits="0" enabled="true" + <spinner bottom="-260" decimal_digits="0" enabled="true" follows="left|top" height="16" increment="1" initial_val="300" label="Away Timeout:" label_width="141" left="10" max_val="600" min_val="30" mouse_opaque="true" name="afk_timeout_spinner" width="202" /> @@ -109,18 +109,18 @@ mouse_opaque="true" name="mini_map_notify_sim" radio_style="false" width="256" /> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-332" drop_shadow_visible="true" enabled="true" follows="left|top" + bottom="-312" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="10" left="10" mouse_opaque="true" name="maturity_desired_label" v_pad="0" width="394"> Rating: </text> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-332" drop_shadow_visible="true" enabled="true" follows="left|top" + bottom="-312" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="10" left="151" mouse_opaque="true" name="maturity_desired_prompt" v_pad="0" width="394"> I want to access content rated: </text> - <combo_box bottom="-338" follows="left|top" height="18" left="320" + <combo_box bottom="-318" follows="left|top" height="18" left="315" mouse_opaque="true" name="maturity_desired_combobox" width="150"> <combo_item name="Desired_Adult" value="42"> PG, Mature and Adult @@ -133,8 +133,8 @@ </combo_item> </combo_box> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-332" drop_shadow_visible="true" enabled="true" follows="left|top" - font="SansSerifSmall" h_pad="0" halign="left" height="10" left="320" + bottom="-312" drop_shadow_visible="true" enabled="true" follows="left|top" + font="SansSerifSmall" h_pad="0" halign="left" height="10" left="315" mouse_opaque="true" name="maturity_desired_textbox" v_pad="0" width="150"> PG only </text> @@ -151,25 +151,25 @@ Nametags: </text> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-175" drop_shadow_visible="true" enabled="true" follows="left|top" + bottom="-155" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="10" left="10" mouse_opaque="true" name="effects_color_textbox" v_pad="0" width="394"> Selection Beam Color: </text> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-274" drop_shadow_visible="true" enabled="true" follows="left|top" + bottom="-254" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="10" left="220" mouse_opaque="true" name="seconds_textbox" v_pad="0" width="128"> seconds </text> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-372" drop_shadow_visible="true" enabled="true" follows="left|top" + bottom="-352" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="18" left="10" mouse_opaque="true" name="time_textbox" v_pad="0" width="394"> Clock: </text> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-404" drop_shadow_visible="true" enabled="true" follows="left|top" + bottom="-384" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="18" left="10" mouse_opaque="true" name="language_textbox" v_pad="0" width="394"> Language: @@ -184,7 +184,7 @@ <string name="region_name_prompt"> <Type region name> </string> - <combo_box allow_text_entry="false" bottom="-372" enabled="true" follows="left|top" + <combo_box allow_text_entry="false" bottom="-352" enabled="true" follows="left|top" height="18" left="153" max_chars="20" mouse_opaque="true" name="time_combobox" width="146"> <combo_item type="string" name="12HourTime" value="PST 12"> @@ -197,7 +197,7 @@ UTC </combo_item> </combo_box> - <combo_box allow_text_entry="true" bottom="-402" enabled="true" + <combo_box allow_text_entry="true" bottom="-382" enabled="true" follows="left|top" height="16" left="153" max_chars="135" mouse_opaque="true" name="language_combobox" width="146"> <combo_item type="string" length="1" enabled="true" name="System Default Language" value="default"> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_graphics1.xml b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_graphics1.xml index 72a643806..2ed0869a6 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_graphics1.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_graphics1.xml @@ -29,9 +29,6 @@ <combo_box allow_text_entry="false" bottom="-67" enabled="true" follows="left|top" height="18" left="185" max_chars="20" mouse_opaque="true" name="windowsize combo" width="150"> - <combo_item type="string" length="1" enabled="true" name="640x480" value="640 x 480"> - 640x480 - </combo_item> <combo_item type="string" length="1" enabled="true" name="800x600" value="800 x 600"> 800x600 </combo_item> @@ -44,8 +41,16 @@ <combo_item type="string" length="1" enabled="true" name="1024x768" value="1024 x 768"> 1024x768 </combo_item> - - </combo_box> + <combo_item type="string" length="1" enabled="true" name="1280x720" value="1280 x 720"> + 1280x720 (HDV720) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="1440x1080" value="1440 x 1080"> + 1440x1080 (HDV1080) + </combo_item> + <combo_item type="string" length="1" enabled="true" name="1920x1080" value="1920 x 1080"> + 1920x1080 (HD1080) + </combo_item> + </combo_box> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" bottom="-62" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="12" left="10" @@ -237,35 +242,21 @@ radio_style="false" width="256" /> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" bottom_delta="-20" drop_shadow_visible="true" enabled="true" follows="left|top" - font="SansSerifSmall" h_pad="0" halign="left" height="12" left_delta="0" + font="SansSerifSmall" h_pad="0" halign="left" height="12" left_delta="0" mouse_opaque="true" name="AvatarCountText" v_pad="0" width="128"> Max. non-imposters: </text> - <slider bottom_delta="-20" can_edit_text="false" control_name="RenderAvatarMaxVisible" + <slider bottom_delta="-20" can_edit_text="true" control_name="RenderAvatarMaxVisible" decimal_digits="0" enabled="true" follows="left|top" height="16" - increment="1" initial_val="35" label="" + increment="1" initial_val="35" label="" label_width="0" left_delta="0" max_val="50" min_val="0" mouse_opaque="true" name="AvatarMaxVisible" show_text="true" width="100" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-131" drop_shadow_visible="true" enabled="true" follows="left|top" - font="SansSerifSmall" h_pad="0" halign="left" height="12" - left="457" mouse_opaque="true" name="DrawDistanceMeterText1" v_pad="0" - width="128"> - m - </text> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-131" drop_shadow_visible="true" enabled="true" follows="left|top" - font="SansSerifSmall" h_pad="0" halign="left" height="12" - left="463" mouse_opaque="true" name="DrawDistanceMeterText2" v_pad="0" - width="128"> - m - </text> - <slider bottom="-135" can_edit_text="false" control_name="RenderFarClip" + <slider bottom="-135" can_edit_text="true" control_name="RenderFarClip" decimal_digits="0" enabled="true" follows="left|top" height="16" - increment="8" initial_val="160" label="Draw distance:" - label_width="140" left="215" max_val="512" min_val="32" mouse_opaque="true" - name="DrawDistance" show_text="true" width="255" /> - <slider bottom_delta="-20" can_edit_text="false" control_name="RenderMaxPartCount" + increment="4" initial_val="160" label="Draw distance (meters):" + label_width="140" left="215" max_val="1024" min_val="32" mouse_opaque="true" + name="DrawDistance" show_text="true" width="262" /> + <slider bottom_delta="-20" can_edit_text="true" control_name="RenderMaxPartCount" decimal_digits="0" enabled="true" follows="left|top" height="16" increment="256" initial_val="4096" label="Max. particle count:" label_width="140" left_delta="0" diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_im.xml b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_im.xml index bb5002b0d..e64f6c76b 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_im.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_im.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel border="true" bottom="-409" enabled="true" follows="left|top|right|bottom" - height="408" label="Communication" left="102" mouse_opaque="true" name="im" + height="408" label="IMs & Logging" left="102" mouse_opaque="true" name="im" width="517"> <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" bottom="-20" drop_shadow_visible="true" enabled="true" follows="left|top" diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml index 70c84644a..3d19a4d8c 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml @@ -24,13 +24,13 @@ follows="left|top" font="SansSerifSmall" height="16" initial_value="false" label="Show avatar in mouselook" left="148" mouse_opaque="true" name="first_person_avatar_visible" radio_style="false" width="256" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" moonworld="false" bottom_delta="-30" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="10" left="10" mouse_opaque="true" name=" Auto Fly Options:" v_pad="0" width="266"> Auto-Fly: </text> - <check_box bottom_delta="-6" enabled="true" follows="left|top" + <check_box bottom_delta="-6" enabled="true" follows="left|top" moonworld="false" font="SansSerifSmall" height="16" label="Fly/land on holding up/down" left="148" mouse_opaque="true" name="automatic_fly" radio_style="false" width="178" /> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_skins.xml b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_skins.xml index 0611ce348..58a2989b4 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_skins.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_skins.xml @@ -5,8 +5,8 @@ <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" bottom="-22" drop_shadow_visible="true" enabled="true" follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="12" left="10" - mouse_opaque="true" name="muting_text" v_pad="0" width="400"> - Select a skin (requires restart). + mouse_opaque="true" name="muting_text" v_pad="0" width="500"> + Select a skin (requires restart). (Please see the skin folders for information and credits) </text> <radio_group bottom="0" draw_border="false" follows="top|left" height="380" left="12" name="skin_selection" width="480"> @@ -40,12 +40,24 @@ scale_image="true" label="" image_selected="skin_thumbnail_gemini.png" image_hover_selected="skin_thumbnail_gemini.png" image_unselected="skin_thumbnail_gemini.png" image_hover_unselected="skin_thumbnail_gemini.png" follows="left|top" /> - - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="10" drop_shadow_visible="true" enabled="true" follows="left|bottom" - font="SansSerifSmall" h_pad="0" halign="left" height="12" left="90" - mouse_opaque="true" name="muting_text" v_pad="0" width="400"> - (Please see the skin folders for information and credits) + <text name="skin_current_text" + left="10" bottom="5" halign="left" height="12" + follows="left|bottom" h_pad="0" v_pad="0" + bg_visible="false" drop_shadow_visible="true" + border_visible="false" border_drop_shadow_visible="false" + font="SansSerif" mouse_opaque="true"> + Other Skin Name: </text> + <line_editor name="skin_current_edit" + bottom_delta="0" left_delta="120" height="20" width="120" + follows="left|bottom" font="SansSerif" + bevel_style="in" border_style="line" border_thickness="1" + max_length="31" mouse_opaque="true" + handle_edit_keys_directly="true" + select_all_on_focus_received="true" /> + <button name="save_skin" label="Save" + bottom_delta="-2" left_delta="120" height="24" width="90" + follows="left|center" font="SansSerif" halign="center" + mouse_opaque="true" scale_image="TRUE" /> </panel> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_voice.xml b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_voice.xml index fc9b6cde8..b4939cae1 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_preferences_voice.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_preferences_voice.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel border="true" bottom="-409" enabled="true" follows="left|top|right|bottom" - height="408" label="Voice Chat" left="102" mouse_opaque="true" name="chat" + height="408" label="Voice" left="102" mouse_opaque="true" name="chat" width="517"> <text_editor type="string" length="1" allow_html="false" bg_readonly_color="0 0 0 0" bottom_delta="-26" embedded_items="false" enabled="false" follows="left|top" diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_radar.xml b/linden/indra/newview/skins/default/xui/en-us/panel_radar.xml index 603f2d81d..4639ef323 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_radar.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_radar.xml @@ -41,15 +41,15 @@ </text> <slider name="near_me_range" label="" control_name="NearMeRange" - bottom_delta="0" left_delta="62" width="110" height="15" - follows="left|top" min_val="5" max_val="512" increment="1" - initial_val="96" decimal_digits="0" /> + bottom_delta="0" left_delta="58" width="110" height="15" + follows="left|top" min_val="5" max_val="1024" increment="1" + initial_val="96" decimal_digits="0" can_edit_text="true" /> <text name="meters" - bottom_delta="0" left="180" height="15" width="40" + bottom_delta="0" left_delta="113" height="15" width="40" h_pad="0" halign="left" v_pad="0" follows="left|top" bg_visible="false" border_drop_shadow_visible="false" - border_visible="false" drop_shadow_visible="true" + border_visible="false" drop_shadow_visible="true" font="SansSerifSmall" mouse_opaque="true"> m </text> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_region_estate.xml b/linden/indra/newview/skins/default/xui/en-us/panel_region_estate.xml index 84ce9d050..5dd738a12 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_region_estate.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_region_estate.xml @@ -25,7 +25,7 @@ regions in the estate. (unknown) </text> <view_border bevel_style="in" border="true" border_thickness="1" bottom_delta="-295" - follows="top|left" height="290" left="6" width="250" /> + follows="top|left" height="350" left="6" width="250" /> <check_box bottom_delta="265" follows="left|top" height="20" label="Use Global Time" left="12" name="use_global_time_check" width="200" /> <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" @@ -69,13 +69,12 @@ regions in the estate. left="12" name="allow_direct_teleport" width="80" /> <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" name="allow_direct_teleport_help" right="250" width="18" /> - <text bottom_delta="-26" follows="left|top" font="SansSerifSmall" height="20" - left="10" name="abuse_email_text" width="180"> - Abuse email address: - </text> - <line_editor bottom_delta="-16" follows="top|left" height="19" left="15" max_length="254" + <text bottom_delta="-26" follows="left|top" font="SansSerifSmall" height="20" + left="10" name="abuse_email_text" width="180"> + Abuse email address: + </text> + <line_editor bottom_delta="-16" follows="top|left" height="19" left="15" max_length="254" name="abuse_email_address" width="205" /> - <string name="email_unsupported">Feature unsupported</string> <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" name="abuse_email_address_help" right="250" width="18" /> <button bottom_delta="-26" enabled="false" follows="left|top" height="20" label="Apply" diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_region_general.xml b/linden/indra/newview/skins/default/xui/en-us/panel_region_general.xml index 6302428c8..70df1df45 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_region_general.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_region_general.xml @@ -58,16 +58,21 @@ <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" left="205" name="parcel_search_help" width="18" /> <spinner bottom_delta="-40" follows="left|top" height="20" increment="1" - label="Agent Limit" label_width="97" left="10" max_val="100" min_val="1" + label="Agent Limit" label_width="100" left="10" max_val="100" min_val="1" name="agent_limit_spin" width="170" /> <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" left="205" name="agent_limit_help" width="18" /> <spinner bottom_delta="-20" follows="left|top" height="20" increment="0.5" - label="Object Bonus" label_width="97" left="10" max_val="10" min_val="1" + label="Object Bonus" label_width="100" left="10" max_val="10" min_val="1" name="object_bonus_spin" width="170" /> <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" left="205" name="object_bonus_help" width="18" /> - <text bottom_delta="-30" follows="left|top" height="20" label="Maturity" left="10" + <spinner bottom_delta="-20" follows="left|top" height="20" increment="0.5" + label="Minimum Agent Age" label_width="100" left="10" max_val="1000" min_val="0" + name="minimum_agent_age" width="170" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="205" name="minimum_agent_age_help" width="18" /> + <text bottom_delta="-30" follows="left|top" height="20" label="Maturity" left="10" name="access_text" width="100"> Rating: </text> @@ -87,7 +92,7 @@ left="205" name="access_help" width="18" /> <button bottom_delta="-30" enabled="false" follows="left|top" height="20" label="Apply" left="108" name="apply_btn" width="100" /> - <button bottom_delta="-60" follows="left|top" height="20" + <button bottom_delta="-40" follows="left|top" height="20" label="Teleport Home One User..." left="10" name="kick_btn" width="250" /> <button bottom_delta="-23" follows="left|top" height="20" label="Teleport Home All Users..." left="10" name="kick_all_btn" width="250" /> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_region_open_region_settings.xml b/linden/indra/newview/skins/default/xui/en-us/panel_region_open_region_settings.xml new file mode 100644 index 000000000..3eb78061f --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/panel_region_open_region_settings.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel border="true" bottom="100" follows="top|left" height="320" label="Region Settings" + left="0" name="RegionSettings" width="480"> + <spinner bottom_delta="-40" follows="left|top" height="20" increment="1" + label="Default Draw Distance" label_width="175" left="10" max_val="10000" min_val="1" + name="draw_distance" width="250" /> + <check_box bottom_delta="-20" follows="left|top" height="20" label="Force Draw Distance" + left="10" name="force_draw_distance" width="80" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="285" name="force_draw_distance_help" width="18" /> + <spinner bottom_delta="-20" follows="left|top" height="20" increment="1" + label="Max Drag Distance" label_width="175" left="10" max_val="1000 0" min_val="0" + name="max_drag_distance" width="250" /> + <spinner bottom_delta="-20" follows="left|top" height="20" increment="1" + label="Max Prim Scale" label_width="175" left="10" max_val="10000" min_val="0" + name="max_prim_scale" width="250" /> + <spinner bottom_delta="-20" follows="left|top" height="20" increment="1" + label="Min Prim Scale" label_width="175" left="10" max_val="10000" min_val="0" + name="min_prim_scale" width="250" /> + <spinner bottom_delta="-20" follows="left|top" height="20" increment="1" + label="Max Physical Prim Scale" label_width="175" left="10" max_val="10000" min_val="0" + name="max_phys_prim_scale" width="250" /> + <spinner bottom_delta="-20" follows="left|top" height="20" increment="1" + label="Max Hollow Size" label_width="175" left="10" max_val="100" min_val="0" + name="max_hollow_size" width="250" /> + <spinner bottom_delta="-20" follows="left|top" height="20" increment="1" + label="Min Hole Size" label_width="175" left="10" max_val="100" min_val="0" + name="min_hole_size" width="250" /> + <spinner bottom_delta="-20" follows="left|top" height="20" increment="1" + label="Max Link Count" label_width="175" left="10" max_val="100000" min_val="0" + name="max_link_count" width="250" /> + <spinner bottom_delta="-20" follows="left|top" height="20" increment="1" + label="Max Link Count Phys" label_width="175" left="10" max_val="100000" min_val="0" + name="max_link_count_phys" width="250" /> + <spinner bottom_delta="-20" follows="left|top" height="20" increment="1" + label="Max Inventory Items To Transfer" label_width="175" left="10" max_val="10000" min_val="-1" + name="max_inventory_items_transfer" width="250" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="285" name="max_inventory_items_transfer_help" width="18" /> + <spinner bottom_delta="-20" follows="left|top" height="20" increment="1" + label="Show Tags" label_width="175" left="10" max_val="2" min_val="0" + name="show_tags" width="250" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="285" name="show_tags_help" width="18" /> + <spinner bottom_delta="-20" follows="left|top" height="20" increment="1" + label="Max Groups" label_width="175" left="10" max_val="1000" min_val="-1" + name="max_groups" width="250" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="285" name="max_groups_help" width="18" /> + <check_box bottom_delta="-20" follows="left|top" height="20" label="Render Water" left="10" + name="render_water" width="80" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="285" name="render_water_help" width="18" /> + <check_box bottom_delta="-20" follows="left|top" height="20" label="Allow Minimap" + left="10" name="allow_minimap" width="80" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="285" name="allow_minimap_help" width="18" /> + <check_box bottom_delta="-20" follows="left|top" height="20" label="Allow Physical Prims" + left="10" name="allow_physical_prims" width="80" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="285" name="allow_physical_prims_help" width="18" /> + <check_box bottom_delta="-20" follows="left|top" height="20" label="Enable Teen Mode" + left="10" name="enable_teen_mode" width="80" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="285" name="enable_teen_mode_help" width="18" /> + <check_box bottom_delta="-20" follows="left|top" height="20" label="Enforce Max Build Constraints" + left="10" name="enforce_max_build" width="80" /> + <check_box bottom_delta="-20" follows="left|top" height="20" + label="Allow Parcel WindLight" left="10" + name="allow_parcel_windlight" + width="80" /> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="18" label="?" + left="285" name="allow_parcel_windlight_help" width="18" /> + <button bottom_delta="-30" enabled="false" follows="left|top" height="20" label="Apply" + left="108" name="apply_ors_btn" width="100" /> +</panel> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_status_bar.xml b/linden/indra/newview/skins/default/xui/en-us/panel_status_bar.xml index 46ba64abc..79d5a48cd 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_status_bar.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_status_bar.xml @@ -8,11 +8,11 @@ follows="left|right|bottom" font="SansSerifSmall" h_pad="0" halign="left" height="18" hover="true" left="561" mouse_opaque="true" name="ParcelNameText" text_color="ParcelTextColor" hover_color="ParcelHoverColor" - tool_tip="Name of land parcel on which you are standing. Click for About Land." + tool_tip="Name of land parcel on which you are standing." v_pad="2" width="1039"> parcel name goes here </text> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" moonworld="false" bottom="-20" disabled_color="BalanceTextColor" drop_shadow_visible="true" enabled="true" follows="right|bottom" font="SansSerifSmall" h_pad="0" halign="right" height="18" left="-210" mouse_opaque="true" @@ -20,7 +20,7 @@ v_pad="2" width="76"> Loading... </text> - <button bottom="-18" enabled="true" follows="right|bottom" font="SansSerifSmall" + <button bottom="-18" enabled="true" follows="right|bottom" font="SansSerifSmall" moonworld="false" halign="center" height="18" image_selected="button_enabled_selected_32x128.tga" image_unselected="button_enabled_32x128.tga" label="[CURRENCY]" @@ -82,7 +82,7 @@ tool_tip="Buy this parcel" visible="false" width="16" /> <!-- Totally unsexy button hack to get a sexy bevel for sexy search bevel -brent --> - <button bottom="-17" height="16" left="-95" width="94" + <button bottom="-17" height="16" left="-95" width="94" moonworld="false" image_unselected="sm_rounded_corners_simple.tga" image_selected="sm_rounded_corners_simple.tga" image_hover_selected="sm_rounded_corners_simple.tga" @@ -91,14 +91,14 @@ image_disabled="sm_rounded_corners_simple.tga" label="" scale_image="true" enabled="true" mouse_opaque="false" name="menubar_search_bevel_bg"/> - <line_editor bevel_style="none" border_style="line" border_thickness="0" border_drop_shadow_visible="false" bottom="-16" + <line_editor bevel_style="none" border_style="line" border_thickness="0" border_drop_shadow_visible="false" bottom="-16" moonworld="false" commit_on_focus_lost="false" enabled="true" follows="right|bottom" font="SansSerifSmall" handle_edit_keys_directly="false" height="11" label="Search" left="-94" max_length="254" mouse_opaque="true" name="search_editor" select_all_on_focus_received="false" select_on_focus="false" tab_group="1" tool_tip="Inworld search" width="78" spell_check="true"/> - <button bottom="-17" enabled="true" follows="right|bottom" font="SansSerifSmall" + <button bottom="-17" enabled="true" follows="right|bottom" font="SansSerifSmall" moonworld="false" halign="center" height="16" image_unselected="status_search_btn.png" image_selected="status_search_btn_pressed.png" image_disabled_selected="status_search_btn_pressed.png" image_disabled="status_search_btn.png" label="" label_selected="" left="-16" mouse_opaque="true" name="search_btn" tool_tip="Search Second Life" width="16" scale_image="false"/> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_toolbar.xml b/linden/indra/newview/skins/default/xui/en-us/panel_toolbar.xml index 7a82674b4..00a6a737c 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_toolbar.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_toolbar.xml @@ -5,8 +5,8 @@ <string name="Redock Windows">Redock Windows</string> <!-- panel bottom="0" filename="panel_bg_toolbar.xml" height="28" left="0" width="1024" /--> - <layout_stack name="toolbar_stack" follows="left|right|bottom|top" bottom="2" left="1" width="1022" height="26" min_width="200" min_height="26" orientation="horizontal" border_size="0"> - <icon image_name="spacer24.tga" width="2" height="2" follows="left|right" auto_resize="false" color="0,0,0,0" left="0" /> + <layout_stack name="toolbar_stack" follows="left|right|bottom|top" bottom="2" left="1" width="1022" height="26" min_width="200" min_height="26" orientation="horizontal" border_size="0" moonworld="true"> + <icon image_name="spacer24.tga" width="2" height="2" follows="left|right" auto_resize="true" color="0,0,0,0" left="0" moonworld="true" /> <button bottom="0" font="SansSerif" height="24" image_selected="btn_chatbar_selected.tga" scale_image="true" image_unselected="btn_chatbar.tga" label="" left="2" name="chat_btn" @@ -26,13 +26,13 @@ label_selected="Stop Flying" left="0" name="fly_btn" tool_tip="Start flying. Use E/C or PgUp/PgDn to fly up and down." width="40" follows="left|right" user_resize="false"/> - <button bottom="0" font="SansSerif" height="24" label="Snapshot" left="0" + <button bottom="0" font="SansSerif" height="24" label="Snapshot" right="-10" moonworld="true" image_overlay="icn_toolbar_snapshot.tga" image_overlay_alignment="left" image_selected="toolbar_btn_selected.tga" image_unselected="toolbar_btn_enabled.tga" image_disabled="toolbar_btn_disabled.tga" scale_image="true" name="snapshot_btn" tool_tip="Save a screen shot to disk or inventory." - width="50" follows="left|right" user_resize="false"/> + width="100" min_width="100" auto_resize="false" follows="right" user_resize="false"/> <button bottom="0" font="SansSerif" height="24" label="Search" left="0" image_overlay="icn_toolbar_search.tga" image_overlay_alignment="left" image_selected="toolbar_btn_selected.tga" @@ -59,12 +59,12 @@ image_disabled="toolbar_btn_disabled.tga" scale_image="true" name="radar_btn" tool_tip="Map of the area around you. (Ctrl-Shift-M)" width="50" follows="left|right" user_resize="false"/> - <button bottom="0" font="SansSerif" height="24" label="Inventory" left="0" + <button bottom="0" font="SansSerif" height="24" label="Inventory" right="-10" moonworld="true" image_overlay="icn_toolbar_inventory.tga" image_overlay_alignment="left" image_selected="toolbar_btn_selected.tga" image_unselected="toolbar_btn_enabled.tga" image_disabled="toolbar_btn_disabled.tga" scale_image="true" - name="inventory_btn" tool_tip="Your items. (Ctrl-I)" width="50" follows="left|right" user_resize="false"/> + name="inventory_btn" tool_tip="Your items. (Ctrl-I)" width="100" min_width="100" auto_resize="false" follows="right" user_resize="false"/> </layout_stack> </panel> diff --git a/linden/indra/newview/skins/default/xui/en-us/panel_windlight_remote_expanded.xml b/linden/indra/newview/skins/default/xui/en-us/panel_windlight_remote_expanded.xml index 3849efd19..c7769cc68 100644 --- a/linden/indra/newview/skins/default/xui/en-us/panel_windlight_remote_expanded.xml +++ b/linden/indra/newview/skins/default/xui/en-us/panel_windlight_remote_expanded.xml @@ -3,24 +3,17 @@ follows="right|bottom" height="67" left="0" mouse_opaque="true" name="windlight_remote" use_bounding_rect="true" width="182"> <panel bottom="1" filename="panel_bg_tab.xml" name="panel_bg_tab" height="67" left="0" width="182" /> - <slider bottom="-20" can_edit_text="false" control_name="RenderFarClip" + <slider bottom="-20" can_edit_text="true" control_name="RenderFarClip" decimal_digits="0" enabled="true" height="18" - increment="8" initial_val="160" label="Draw distance:" - label_width="78" left="6" max_val="512" min_val="32" mouse_opaque="true" - name="DrawDistance" show_text="true" width="170" /> - <slider bottom_delta="-20" can_edit_text="false" control_name="RenderMaxPartCount" + increment="4" initial_val="160" label="Draw distance:" + label_width="74" left="4" max_val="1024" min_val="32" mouse_opaque="true" + name="DrawDistance" show_text="true" width="174" /> + <slider bottom_delta="-20" can_edit_text="true" control_name="RenderMaxPartCount" decimal_digits="0" enabled="true" follows="left|top" height="18" increment="256" initial_val="4096" - label="Max. particles:" label_width="78" left_delta="0" + label="Max. particles:" label_width="74" left_delta="0" max_val="8192" min_val="0" mouse_opaque="true" name="MaxParticleCount" - show_text="true" width="176" /> - <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" - bottom="-14" drop_shadow_visible="true" enabled="true" follows="left|top" - font="SansSerifSmall" h_pad="0" halign="left" height="12" - left="170" mouse_opaque="true" name="DrawDistanceMeterText2" v_pad="0" - width="8"> - m - </text> + show_text="true" width="174" /> <panel bottom="13" filename="panel_windlight_controls.xml" left="0" width="182" /> <string name="atmosphere"> Atmosphere diff --git a/linden/indra/newview/skins/default/xui/en-us/strings.xml b/linden/indra/newview/skins/default/xui/en-us/strings.xml index ceb699480..d3c9df13c 100644 --- a/linden/indra/newview/skins/default/xui/en-us/strings.xml +++ b/linden/indra/newview/skins/default/xui/en-us/strings.xml @@ -23,6 +23,12 @@ <string name="copy_obj_key_info"> Copied key(s) for: </string> + <string name="TeleportOfferMaturity"> + [NAME] is offering a TP to [DESTINATION] + </string> + <string name="TeleportLureMaturity"> + [NAME]'s teleport lure is to [DESTINATION] + </string> <!-- Login --> <string name="LoginInProgress">Logging in. [APP_NAME] may appear frozen. Please wait.</string> diff --git a/linden/indra/newview/skins/default/xui/fr/panel_preferences_advanced.xml b/linden/indra/newview/skins/default/xui/fr/panel_preferences_advanced.xml index 0c30199ac..4f33ae4ef 100644 --- a/linden/indra/newview/skins/default/xui/fr/panel_preferences_advanced.xml +++ b/linden/indra/newview/skins/default/xui/fr/panel_preferences_advanced.xml @@ -1,4 +1,183 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<panel name="advanced_panel"> - <check_box label="Partager la langue avec les objets" name="language_is_public" tool_tip="Cette option permet de faire connaître aux objets du Monde votre langue favorite."/> -</panel> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel border="true" bottom="-409" enabled="true" follows="left|top|right|bottom" + height="408" label="Avancé" left="102" mouse_opaque="true" + name="advanced_panel" width="517"> + <!-- Start organizing these when we get enough of 'em - MC --> + <tab_container label="Page 2" bottom="0" height="450" left="0" mouse_opaque="false" + name="tab2" tab_min_width="50" tab_position="top" width="495" bg_opaque_color="0,0,0,0.0"> + + <panel border="true" bottom="-409" enabled="true" follows="left|top|right|bottom" + height="408" label="Main" left="102" mouse_opaque="true" + name="main_panel" width="517"> + <check_box label="Désactiver l'écrant de Connexion/Déconnexion" name="disable_log_screen_check" /> + <check_box label="Désactiver l'écrant de téléportation" name="disable_tp_screen_check" /> + <check_box label="Afficher les noms de clients dans les titres" name="client_name_tag_check"/> + <check_box label="Afficher les noms de clients avec la couleur" name="client_name_color_check"/> + <check_box label="Afficher les noms de clients dans les infos-bulles" name="client_name_hover_check" /> + <check_box label="Afficher le nom de votre clien pour les residents" name="client_name_tag_broadcast_check" radio_style="false" width="217" /> + <check_box label="Activer les Ombres (ATTENTION: instable et les graphiques Ultra sont requis)" name="shadows_check"/> + <text bottom_delta="-25" left="16" height="15" width="300" + follows="top|left"> + Laisser la région gèrer le WindLight (LightShare): + </text> + <combo_box name="lightshare_combo" + bottom_delta="-2" left_delta="250" height="18" width="135" + allow_text_entry="false" follows="left|top"> + <combo_item type="string" name="never" value="0"> + Jamais + </combo_item> + <combo_item type="string" name="ask" value="1"> + Toujours me le demander + </combo_item> + <combo_item type="string" name="always" value="2"> + Toujours + </combo_item> + </combo_box> + <check_box label="Utiliser le raffraichissement de texture HTTP (experimental)" name="http_texture_check" /> + <check_box label="Augmenter la vitesse de rez par une vue moins progressive" name="speed_rez_check"/> + <spinner label="Intervalle de chaque étapes:" name="speed_rez_interval_spinner" /> + <text bottom_delta="0" follows="top|left" height="15" left_delta="150" + name="speed_rez_seconds_text" width="115"> + secondes + </text> + <check_box label="Animer votre avatar quand vous êtes en mode apparence" name="appearance_anim_check"/> + <check_box label="Utiliser l'ancien menu de sélection" name="legacy_pie_menu_checkbox"/> + <check_box label="Partager la langue de votre client avec l'objet" name="language_is_public"/> + <check_box bottom_delta="-25" enabled="true" + follows="left|top" font="SansSerifSmall" height="16" hidden="false" + initial_value="false" label="Use MU* pose style chat and IM" left="12" + mouse_opaque="true" name="allow_mupose" + radio_style="false" tool_tip="Use MU* pose style in chat and IM (with ':' as a synonymous to '/me ')." + width="256" /> + <check_box bottom_delta="0" enabled="true" + follows="left|top" font="SansSerifSmall" height="16" hidden="false" + initial_value="false" label="Auto-close OOC (( )) chat" left_delta="250" + mouse_opaque="true" name="auto_close_ooc" + radio_style="false" tool_tip="Auto-close OOC chat (i.e. add )) if not found and (( was used)." + width="256" /> + <check_box bottom_delta="-25" enabled="true" follows="left|top" font="SansSerifSmall" height="16" + initial_value="false" label="Use the chatbar as a command line" left="12" + mouse_opaque="true" name="command_line_check" radio_style="false" width="270"/> + <button bottom_delta="-20" follows="left|top" font="SansSerif" height="20" width="150" + label="Chatbar Commands" name="command_line_btn" left="12" + tool_tip="Set specific chatbar command line commands here" /> + + <!-- Uncomment when we start using the crash logger - MC --> + <!--<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom_delta="-30" drop_shadow_visible="true" enabled="true" follows="left|top" + font="SansSerifSmall" h_pad="0" halign="left" height="18" left="12" + mouse_opaque="true" name="crash_report_textbox" v_pad="0" width="394"> + Crash reports: + </text> + <combo_box allow_text_entry="false" bottom_delta="0" enabled="true" follows="left|top" + height="18" left="153" max_chars="20" mouse_opaque="true" + name="crash_behavior_combobox" width="146"> + <combo_item type="string" length="1" enabled="true" name="Askbeforesending" value="Ask before sending"> + Ask before sending + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Alwayssend" value="Always send"> + Always send + </combo_item> + <combo_item type="string" length="1" enabled="true" name="Neversend" value="Never send"> + Never send + </combo_item> + </combo_box>--> + + <button bottom="10" follows="left|bottom" font="SansSerif" height="20" width="250" + label="Reset All Preferences To Default" name="reset_btn" left="12" + tool_tip="Reset all preferences to their default values (requires a restart)" /> + </panel> + + <panel border="true" bottom="-580" follows="left|top|right|bottom" height="525" label="SpellCheck" + left="1" mouse_opaque="true" name="SpellCheck" width="418"> + <button bottom="-25" follows="left|top" font="SansSerifSmall" height="18" label="?" + name="EmeraldHelp_SpellCheck" tool_tip="Click here for help regarding the settings in this page." + right="490" width="18"/> + <check_box bottom="-25" enabled="true" follows="left|top" font="SansSerifSmall" height="16" + label="Show misspelled words in red" left="12" mouse_opaque="true" name="EmeraldSpellDisplay" + control_name="EmeraldSpellDisplay" width="126"/> + <text bottom_delta="-30" follows="left|top" font="SansSerifSmall" height="16" left="12" + name="EmSpell_txt1" width="512"> + Current language (dictionary): + </text> + <combo_box allow_text_entry="false" bottom_delta="-20" left_delta="0" follows="left|top" height="18" + max_chars="200" mouse_opaque="true" name="EmeraldSpellBase" width="250" + control_name="EmeraldSpellBase" tool_tip=""/> + <text bottom_delta="-30" follows="left|top" font="SansSerifSmall" height="16" left="12" + name="EmSpell_txt3" width="512"> + Downloaded languages (dictionaries): + </text> + <combo_box allow_text_entry="false" bottom_delta="-20" left_delta="0" follows="left|top" height="18" + max_chars="200" mouse_opaque="true" name="EmSpell_Avail" width="250" + control_name="EmSpell_Avail" tool_tip=""/> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="20" label="Install" + name="EmSpell_Add" tool_tip="" left_delta="255" width="80"/> + <button bottom_delta="-22" follows="left|top" font="SansSerifSmall" height="20" label="Download More..." + name="EmSpell_GetMore" tool_tip="Get more dictionaries availabe online" left="12" width="250"/> + <text bottom_delta="-30" follows="left|top" font="SansSerifSmall" height="16" left="12" + name="EmSpell_txt2" width="512"> + Additional custom languages (dictionaries): + </text> + <combo_box allow_text_entry="false" bottom_delta="-20" left_delta="0" follows="left|top" height="18" + max_chars="200" mouse_opaque="true" name="EmSpell_Installed" width="250" + control_name="EmSpell_Installed" tool_tip=""/> + <button bottom_delta="0" follows="left|top" font="SansSerifSmall" height="20" label="Remove" + name="EmSpell_Remove" tool_tip="" left_delta="255" width="80"/> + <!--<button bottom_delta="-20" follows="left|top" font="SansSerifSmall" height="18" label="Edit Custom dictionary" + name="EmSpell_EditCustom" tool_tip="" left_delta="20" width="130"/>--> + <text bottom_delta="-30" follows="left|top" font="SansSerifSmall" height="16" left="12" + name="EmSpell_txt4" width="512"> +To use spellcheck, right-click a misspelled word +(red or otherwise) and select its replacement + </text> + <button name="ac_button" label="AutoCorrect Options..." halign="center" + tool_tip="Modify the AutoCorrect word list and settings" left="12" + bottom_delta="-50" width="180" height="20" font="SansSerifSmall" follows="left|top"/> + </panel> + + <panel border="true" bottom="-580" follows="left|top|right|bottom" height="525" label="Extra" + left="1" mouse_opaque="true" name="Extra" width="418"> + + <check_box bottom_delta="-30" enabled="true" follows="left|top" font="SansSerifSmall" height="16" + initial_value="true" label="Show chat messages from friends in a different color" left="12" + mouse_opaque="true" name="HighlightFriendsChat" radio_style="false" width="270"/> + + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-100" + can_apply_immediately="true" color="1 1 1 1" control_name="FriendsChatColor" + enabled="true" follows="left|top" height="67" label="Friends" left_delta="68" + mouse_opaque="true" name="FriendsChatColor" width="65" /> + + <check_box bottom_delta="-30" enabled="true" follows="left|top" + font="SansSerifSmall" height="16" initial_value="true" + label="Show chat messages containing your name in a different color" left="12" mouse_opaque="true" + name="HighlightOwnNameInChat" radio_style="false" width="217" /> + + <check_box bottom_delta="-30" enabled="true" follows="left|top" font="SansSerifSmall" height="16" + initial_value="true" label="Show GroupIM messages containing your name in a different color" left="12" + mouse_opaque="true" name="HighlightOwnNameInIM" radio_style="false" width="270"/> + + <color_swatch border_color="0.45098 0.517647 0.607843 1" bottom="-230" + can_apply_immediately="true" color="1 1 1 1" control_name="OwnNameChatColor" + enabled="true" follows="left|top" height="67" label="Own Name" left_delta="68" + mouse_opaque="true" name="OwnNameChatColor" width="65" /> + + <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="-50" + enabled="true" follows="left|top" font="SansSerif" + handle_edit_keys_directly="true" height="20" left_delta="0" + max_length="50" mouse_opaque="true" name="nick01" + select_all_on_focus_received="true" width="400" word_wrap="false" /> + + <text bottom_delta="-3" follows="left|top" font="SansSerifSmall" height="20" left="20" name="nick01_text" width="70">Nick 1</text> + + <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="-30" + enabled="true" follows="left|top" font="SansSerif" + handle_edit_keys_directly="true" height="20" left_delta="60" + max_length="50" mouse_opaque="true" name="nick02" + select_all_on_focus_received="true" width="400" word_wrap="false" /> + + <text bottom_delta="-3" follows="left|top" font="SansSerifSmall" height="20" left="20" name="nick02_text" width="70">Nick 2</text> + + <line_editor bevel_style="in" border_style="line" border_thickness="1" bottom_delta="-30" + enabled="true" follows="left|top" font="SansSerif" + handle_edit_keys_directly="true" height="20" left_delta="60" + max_length="50" mouse_opaque="true" name="nick03" diff --git a/linden/indra/newview/skins/default/xui/fr/panel_preferences_audio.xml b/linden/indra/newview/skins/default/xui/fr/panel_preferences_audio.xml index 78475bd34..d4574d107 100644 --- a/linden/indra/newview/skins/default/xui/fr/panel_preferences_audio.xml +++ b/linden/indra/newview/skins/default/xui/fr/panel_preferences_audio.xml @@ -15,6 +15,7 @@ <check_box label="Couper le son lorsque la fenêtre est minimisée" name="mute_when_minimized"/> <check_box bottom="-200" height="32" label="Jouer la musique disponible (consommateur en bande passante)" name="streaming_music"/> + <check_box bottom_delta="-30" label="Afficher le titre de la chanson" name="show_stream_title"/> <check_box bottom_delta="-32" height="32" label="Jouer le média disponible (consommateur en bande passante)" name="streaming_video"/> <check_box bottom_delta="-32" label="Lire automatiquement le média" name="auto_streaming_video"/> @@ -22,5 +23,6 @@ <slider label="Facteur d'éloignement" label_width="115" name="Distance Factor"/> <slider label="Facteur d'atténuation" label_width="115" name="Rolloff Factor"/> <spinner label="Alerte L$" name="L$ Change Threshold"/> - <spinner label="Alerte santé" name="Health Change Threshold"/> + <spinner label="Alerte santé" name="Health change threshold"/> + <check_box label="Desactiver le bruit du vent" name="mute_wind_check"/> </panel> diff --git a/linden/indra/newview/skins/default/xui/fr/panel_preferences_im.xml b/linden/indra/newview/skins/default/xui/fr/panel_preferences_im.xml index 2e7efd31e..af5f846a9 100644 --- a/linden/indra/newview/skins/default/xui/fr/panel_preferences_im.xml +++ b/linden/indra/newview/skins/default/xui/fr/panel_preferences_im.xml @@ -8,9 +8,17 @@ se connecter pour changer </text> <check_box label="Envoyer les IM à mon adresse e-mail ([EMAIL])" name="send_im_to_email"/> - <check_box label="Afficher les IM dans la console du chat" name="include_im_in_chat_console"/> - <check_box label="Afficher l'heure dans les IM" name="show_timestamps_check"/> - <check_box label="Me prévenir quand des amis se connectent" name="friends_online_notify_checkbox"/> + <check_box bottom="-90" label="La console chat" name="include_im_in_chat_console" left="160"/> + <check_box bottom="-90" label="La fenêtre communiquer" name="include_im_in_chat_history" left="260" /> + <text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false" + bottom="-60" drop_shadow_visible="true" enabled="true" follows="left|top" + font="SansSerifSmall" h_pad="0" halign="left" height="10" left="160" + mouse_opaque="false" name="show_ims_label" v_pad="0" width="100"> + Afficher les IMs dans: + </text> + <check_box bottom="-120" label="Afficher l'heure dans les IM" name="show_timestamps_check"/> + <check_box bottom="-140" label="Me prévenir quand des amis se connectent" name="friends_online_notify_checkbox"/> + <check_box label="Afficher les IMs verticalement (redémarrage requis)" name="vertical-imtabs-toggle"/> <text name="text_box3"> Réponse si occupé(e) : </text> @@ -24,8 +32,8 @@ <check_box label="Inclure les heures" name="log_chat_timestamp"/> <check_box label="Inclure les IM reçus" name="log_chat_IM"/> <check_box label="Inclure la date avec les heures" name="log_date_timestamp"/> - <button label="Changer d'emplacement" label_selected="Changer d'emplacement" name="log_path_button" width="150"/> - <line_editor left="308" name="log_path_string" right="-20"/> + <button label="Changer d'emplacement" label_selected="Changer d'emplacement" name="log_path_button" left="145" width="170"/> + <line_editor left="320" name="log_path_string" right="-20"/> <text length="1" name="text_box2" type="string"> IM : </text> diff --git a/linden/indra/newview/skins/default/xui/ja/menu_mini_map.xml b/linden/indra/newview/skins/default/xui/ja/menu_mini_map.xml index c8828a50b..bdd63e834 100644 --- a/linden/indra/newview/skins/default/xui/ja/menu_mini_map.xml +++ b/linden/indra/newview/skins/default/xui/ja/menu_mini_map.xml @@ -3,6 +3,9 @@ <menu_item_call label="ズーム(近)" name="Zoom Close"/> <menu_item_call label="ズーム(中)" name="Zoom Medium"/> <menu_item_call label="ズーム(遠)" name="Zoom Far"/> + <menu_item_check label="カメラを中央に" name="Center on Camera"/> + <menu_item_check label="ミニマップを回転" name="Rotate Mini-Map"/> + <menu_itemcall label="世界地図を表示" name="Show Map"/> <menu_item_call label="追跡をやめる" name="Stop Tracking"/> <menu_item_call label="プロフィール..." name="Profile"/> </menu> diff --git a/linden/indra/newview/skins/default/xui/ja/menu_viewer.xml b/linden/indra/newview/skins/default/xui/ja/menu_viewer.xml index c69c2e305..bc263bbe4 100644 --- a/linden/indra/newview/skins/default/xui/ja/menu_viewer.xml +++ b/linden/indra/newview/skins/default/xui/ja/menu_viewer.xml @@ -1,26 +1,39 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <menu_bar name="Main Menu"> + + + <!-- ファイル --> + <menu label="ファイル" name="File"> <tearoff_menu label="~~~~~~~~~~~" name="~~~~~~~~~~~"/> - <menu label="アップロード" name="upload"> - <menu_item_call label="画像 (L$[COST])..." name="Upload Image"/> - <menu_item_call label="サウンド (L$[COST])..." name="Upload Sound"/> - <menu_item_call label="アニメーション (L$[COST])..." name="Upload Animation"/> - <menu_item_call label="一括 (ファイルにつきL$[COST])..." name="Bulk Upload"/> + <menu label="アップロード" name="Upload"> + <menu_item_call label="画像 ([UPLOADFEE])..." name="Upload Image"/> + <menu_item_call label="サウンド ([UPLOADFEE])..." name="Upload Sound"/> + <menu_item_call label="アニメーション ([UPLOADFEE])..." name="Upload Animation"/> + <menu_item_call label="一括 (ファイルにつき[UPLOADFEE])..." name="Bulk Upload"/> <menu_item_separator label="-----------" name="separator"/> <menu_item_call label="デフォルト権限の設定..." name="perm prefs"/> </menu> <menu_item_separator label="-----------" name="separator"/> + <menu_item_call label="オブジェクトのインポート..." name="Import"/> + <menu_item_call label="インポートとアップロード... (テクスチャにつき[UPLOADFEE])" name="ImportUpload"/> + <menu_item_call label="選択したオブジェクトのエクスポート..." name="Export"/> + <menu_item_separator label="-----------" name="separator2"/> + <menu_item_call label="全てののウィンドウを最小化" name="Minimize All Windows"/> <menu_item_call label="ウィンドウを閉じる" name="Close Window"/> <menu_item_call label="全てのウィンドウを閉じる" name="Close All Windows"/> - <menu_item_separator label="-----------" name="separator2"/> - <menu_item_call label="テクスチャーを別名で保存..." name="Save Texture As..."/> <menu_item_separator label="-----------" name="separator3"/> + <menu_item_call label="テクスチャーを別名で保存..." name="Save Texture As..."/> + <menu_item_separator label="-----------" name="separator4"/> <menu_item_call label="スナップショットを撮る" name="Take Snapshot"/> <menu_item_call label="スナップショットをディスクに保存" name="Snapshot to Disk"/> - <menu_item_separator label="-----------" name="separator4"/> + <menu_item_separator label="-----------" name="separator5"/> <menu_item_call label="終了" name="Quit"/> </menu> + + + <!-- 編集 --> + <menu label="編集" name="Edit"> <menu_item_call label="元に戻す" name="Undo"/> <menu_item_call label="やり直し" name="Redo"/> @@ -51,16 +64,21 @@ <menu_item_call label="スカート" name="Skirt"/> <menu_item_call label="すべての服" name="All Clothes"/> </menu> + <menu_item_call label="容姿の再描画" name="Refresh Appearance"/> <menu_item_separator label="-----------" name="separator6"/> - <menu_item_call label="ジェスチャー…" name="Gestures..."/> + <menu_item_call label="ジェスチャー" name="Gestures"/> <menu_item_call label="プロフィール..." name="Profile..."/> <menu_item_call label="容姿..." name="Appearance..."/> <menu_item_separator label="-----------" name="separator7"/> - <menu_item_check label="フレンド..." name="Friends..."/> - <menu_item_call label="グループ..." name="Groups..."/> + <menu_item_check label="フレンド" name="Friends"/> + <menu_item_call label="グループ" name="Groups"/> <menu_item_separator label="-----------" name="separator8"/> <menu_item_call label="環境設定..." name="Preferences..."/> </menu> + + + <!-- 表示 --> + <menu label="表示" name="View"> <tearoff_menu label="~~~~~~~~~~~" name="~~~~~~~~~~~"/> <menu_item_call label="一人称視点(マウスルック)" name="Mouselook"/> @@ -69,23 +87,27 @@ <menu_item_call label="表示をリセット" name="Reset View"/> <menu_item_call label="最後のチャットを閲覧" name="Look at Last Chatter"/> <menu_item_separator label="-----------" name="separator"/> + <menu_item_call label="ウェブ・ブラウザ" name="Web Browser"/> + <menu_item_separator label="-----------" name="separator2"/> <menu_item_check label="ツールバー" name="Toolbar"/> <menu_item_check label="ローカル・チャット" name="Chat History"/> <menu_item_check label="コミュニケーション" name="Instant Message"/> <menu_item_check label="持ち物" name="Inventory"/> <menu_item_check label="ボイスチャット・ユーザー一覧" name="Active Speakers"/> <menu_item_check label="無視リスト" name="Mute List"/> - <menu_item_separator label="-----------" name="separator2"/> + <menu_item_separator label="-----------" name="separator3"/> <menu_item_check label="カメラ・コントロール" name="Camera Controls"/> <menu_item_check label="移動コントロール" name="Movement Controls"/> <menu_item_check label="世界地図" name="World Map"/> <menu_item_check label="ミニマップ" name="Mini-Map"/> - <menu_item_separator label="-----------" name="separator3"/> + <menu_item_separator label="-----------" name="separator4"/> + <menu_item_call label="AO" name="AO"/> + <menu_item_separator label="-----------" name="separator5"/> <menu_item_check label="地域の統計情報" name="Statistics Bar"/> <menu_item_check label="土地の境界線" name="Property Lines"/> <menu_item_check label="立入禁止ライン" name="Banlines"/> <menu_item_check label="土地オーナー" name="Land Owners"/> - <menu_item_separator label="-----------" name="separator4"/> + <menu_item_separator label="-----------" name="separator6"/> <menu label="ヒントのポップアップ" name="Hover Tips"> <menu_item_check label="ヒントを表示" name="Show Tips"/> <menu_item_separator label="-----------" name="separator"/> @@ -96,14 +118,21 @@ <menu_item_check label="ビーコン(標識)" name="beacons"/> <menu_item_check label="パーティクルを非表示" name="Hide Particles"/> <menu_item_check label="HUD装着物を表示" name="Show HUD Attachments"/> - <menu_item_separator label="-----------" name="separator5"/> - <menu_item_call label="カメラ・ズームイン" name="Zoom In"/> - <menu_item_call label="カメラ・デフォルト" name="Zoom Default"/> - <menu_item_call label="カメラ・ズームアウト" name="Zoom Out"/> - <menu_item_separator label="-----------" name="separator6"/> + <menu_item_separator label="-----------" name="separator7"/> + <menu label="ズーム" name="Zoom Level"> + <menu_item_call label="カメラ・ズームイン" name="Zoom In"/> + <menu_item_call label="カメラ・デフォルト" name="Zoom Default"/> + <menu_item_call label="カメラ・ズームアウト" name="Zoom Out"/> + </menu> <menu_item_call label="[全画面表示]" name="Toggle Fullscreen"/> <menu_item_call label="UIサイズを標準設定に戻す" name="Set UI Size to Default"/> + <menu_item_separator label="-----------" name="separator8"/> + <menu_item_check label="アドバンスメニューを表示" name="Toggle Advanced Menu"/> </menu> + + + <!-- 世界 --> + <menu label="世界" name="World"> <menu_item_call label="チャット" name="Chat"/> <menu_item_check label="常に走る" name="Always Run"/> @@ -116,9 +145,11 @@ <menu_item_separator label="-----------" name="separator3"/> <menu_item_call label="離席中に設定" name="Set Away"/> <menu_item_call label="取り込み中に設定" name="Set Busy"/> + <menu_item_call label="IMに自動応答する" name="Auto-Respond to IMs"/> + <menu_item_separator label="-----------" name="separator4"/> <menu_item_call label="自分のアバターのアニメーションを停止" name="Stop Animating My Avatar"/> <menu_item_call label="キー制御を解除" name="Release Keys"/> - <menu_item_separator label="-----------" name="separator4"/> + <menu_item_separator label="-----------" name="separator5"/> <menu_item_call label="アカウントの履歴..." name="Account History..."> <on_click name="AccountHistory_url" userdata="WebLaunchAccountHistory,http://secondlife.com/account/transactions.php?lang=ja"/> </menu_item_call> @@ -126,12 +157,12 @@ <on_click name="ManageMyAccount_url" userdata="WebLaunchJoinNow,http://secondlife.com/account/index.php?lang=ja"/> </menu_item_call> <menu_item_call label="L$(リンデン・ドル)を購入" name="Buy and Sell L$..."/> - <menu_item_separator label="-----------" name="separator5"/> - <menu_item_call label="自分の土地..." name="My Land..."/> - <menu_item_call label="土地情報..." name="About Land..."/> - <menu_item_call label="土地を購入..." name="Buy Land..."/> - <menu_item_call label="地域/不動産..." name="Region/Estate..."/> <menu_item_separator label="-----------" name="separator6"/> + <menu_item_call label="自分の土地" name="My Land"/> + <menu_item_call label="土地情報" name="About Land"/> + <menu_item_call label="土地を購入..." name="Buy Land..."/> + <menu_item_call label="地域/不動産" name="Region/Estate"/> + <menu_item_separator label="-----------" name="separator7"/> <menu label="環境の設定" name="Environment Settings"> <menu_item_call label="日の出" name="Sunrise"/> <menu_item_call label="正午" name="Noon"/> @@ -142,6 +173,10 @@ <menu_item_call label="環境編集" name="Environment Editor"/> </menu> </menu> + + + <!-- ツール --> + <menu label="ツール" name="Tools"> <menu label="ツールを選ぶ" name="Select Tool"> <menu_item_call label="フォーカス" name="Focus"/> @@ -151,28 +186,43 @@ <menu_item_call label="土地" name="Land"/> </menu> <menu_item_separator label="-----------" name="separator"/> - <menu_item_check label="自分のオブジェクトのみ選択" name="Select Only My Objects"/> - <menu_item_check label="移動可能なオブジェクトのみ選択" name="Select Only Movable Objects"/> - <menu_item_check label="環境で選択" name="Select By Surrounding"/> - <menu_item_check label="隠れた位置の選択も表示" name="Show Hidden Selection"/> - <menu_item_check label="選択したものの光源範囲を表示" name="Show Light Radius for Selection"/> - <menu_item_check label="選択ビームを表示" name="Show Selection Beam"/> + <menu_item_call label="選択対象に視点移動" name="Focus on Selection"/> + <menu_item_call label="選択範囲にズームイン" name="Zoom to Selection"/> + <menu label="選択オプション" name="Selection Options"> + <menu_item_check label="自分のオブジェクトのみ選択" name="Select Only My Objects"/> + <menu_item_check label="移動可能なオブジェクトのみ選択" name="Select Only Movable Objects"/> + <menu_item_check label="コピー可能なオブジェクトのみ選択" name="Select Only Copyable Objects"/> + <menu_item_check label="環境で選択" name="Select By Surrounding"/> + <menu_item_separator label="-----------" name="separator"/> + <menu_item_check label="隠れた位置の選択も表示" name="Show Hidden Selection"/> + <menu_item_check label="選択したものの光源範囲を表示" name="Show Light Radius for Selection"/> + <menu_item_check label="選択したものの輪郭を表示" name="Show Selection Outlines"/> + <menu_item_check label="選択ビームを表示" name="Show Selection Beam"/> + </menu> <menu_item_separator label="-----------" name="separator2"/> <menu_item_check label="グリッドにスナップ" name="Snap to Grid"/> <menu_item_call label="オブジェクトのXY移動をグリッドに合わせる" name="Snap Object XY to Grid"/> <menu_item_call label="グリッドをオブジェクトの位置基準で再設定" name="Use Selection for Grid"/> <menu_item_call label="グリッドのオプション..." name="Grid Options..."/> + <menu_item_call label="高度な制作オプション" name="Advanced Build Options..."/> <menu_item_separator label="-----------" name="separator3"/> <menu_item_check label="リンクされた一部を編集" name="Edit Linked Parts"/> + <menu label="リンクした部分を選択する" name="Select Linked Parts"> + <menu_item_call label="次の部分を選択する" name="Select Next Part"/> + <menu_item_call label="前回の部分を選択する" name="Select Previous Part"/> + <menu_item_call label="次の部分を含める" name="Include Next Part"/> + <menu_item_call label="前回の部分を含める" name="Include Previous Part"/> + </menu> <menu_item_call label="リンク" name="Link"/> <menu_item_call label="リンク解除" name="Unlink"/> <menu_item_separator label="-----------" name="separator4"/> - <menu_item_call label="選択対象に視点移動" name="Focus on Selection"/> - <menu_item_call label="選択範囲にズームイン" name="Zoom to Selection"/> + <menu_item_call label="複製" name="Duplicate"/> <menu_item_call label="オブジェクトを購入" name="Menu Object Take"> <on_enable userdata="購入,取る" name="EnableBuyOrTake"/> </menu_item_call> <menu_item_call label="コピーを取る" name="Take Copy"/> + <menu_item_separator label="-----------" name="separator5"/> + <menu_item_call label="オブジェクトを返却" name="Return..."/> <menu_item_call label="オブジェクトをオブジェクト・コンテンツに戻して保存" name="Save Object Back to Object Contents"/> <menu_item_separator label="-----------" name="separator6"/> <menu_item_call label="スクリプト警告/エラー・ウィンドウを表示" name="Show Script Warning/Error Window"/> @@ -183,37 +233,274 @@ <menu_item_call label="選択したオブジェクトの中のスクリプトをリセット" name="Reset Scripts in Selection"/> <menu_item_call label="選択したオブジェクトの中のスクリプトを起動する" name="Set Scripts to Running in Selection"/> <menu_item_call label="選択したオブジェクトの中のスクリプトを停止する" name="Set Scripts to Not Running in Selection"/> + <menu_item_separator label="-----------" name="separator7"/> + <menu_item_call label="一括権限設定" name="Set permissions on selected task inventory"/> </menu> + + + <!-- ヘルプ --> + <menu label="ヘルプ" name="Help"> - <menu_item_call label="Second Life ヘルプ" name="Second Life Help"/> + <menu_item_call label="ヘルプ" name="Grid Help"/> <menu_item_call label="チュートリアル" name="Tutorial"/> <menu_item_separator label="-----------" name="separator"/> - <menu_item_call label="Linden公式ブログ..." name="Official Linden Blog..."/> + <menu_item_call label="Imprudenceブログ" name="Imprudence Blog"/> + <menu_item_call label="Imprudenceフォーラム" name="Imprudence Forums"/> <menu_item_separator label="-----------" name="separator2"/> - <menu_item_call label="スクリプト・ポータル..." name="Scripting Portal..."> + <menu_item_call label="スクリプト・ポータル" name="Scripting Portal"> <on_click name="ScriptingPortal_url" userdata="WebLaunchLSLWiki,http://wiki.secondlife.com/wiki/LSL_Portal/ja" /> </menu_item_call> <menu_item_separator label="-----------" name="separator3"/> <menu_item_call label="嫌がらせの報告..." name="Report Abuse..."/> - <menu_item_call label="衝突の記録..." name="Bumps, Pushes &amp; Hits..."/> + <menu_item_call label="衝突の記録" name="Bumps, Pushes &amp; Hits"/> <menu_item_call label="ラグ メーター" name="Lag Meter"/> - <menu_item_separator label="-----------" name="separator7"/> - <menu label="バグの報告" name="Bug Reporting"> - <menu_item_call label="パブリック問題トラッカー..." name="Public Issue Tracker..."/> - <menu_item_call label="パブリック問題トラッカー ヘルプ..." name="Publc Issue Tracker Help..."> - <on_click name="PublicIssueTrackerHelp_url" userdata="WebLaunchPublicIssueHelp,http://wiki.secondlife.com/wiki/Issue_tracker/ja" /> - </menu_item_call> - <menu_item_separator label="-----------" name="separator7"/> - <menu_item_call label="バグの報告 101..." name="Bug Reporing 101..."> - <on_click name="BugReporting101_url" userdata="WebLaunchBugReport101,http://wiki.secondlife.com/wiki/Bug_Reporting_101"/> - </menu_item_call> - <menu_item_call label="セキュリティ問題..." name="Security Issues..."> - <on_click name="SecurityIssues_url" userdata="WebLaunchSecurityIssues,http://wiki.secondlife.com/wiki/Security_issues/ja"/> - </menu_item_call> - <menu_item_call label="品質保証関連Wiki..." name="QA Wiki..."/> - <menu_item_separator label="-----------" name="separator9"/> - <menu_item_call label="バグの報告..." name="Report Bug..."/> - </menu> - <menu_item_call label="Second Lifeについて" name="About Second Life..."/> + <menu_item_separator label="-----------" name="separator4"/> + <menu_item_call label="Imprudenceについて" name="About Imprudence"/> + </menu> + + + <!-- アドバンス--> + + <menu label="アドバンス" name="Advanced" drop_shadow="true"> + <menu label="コンソール" name="Consoles"> + <menu_item_check label="フレームのコンソール" name="Frame Console"/> + <menu_item_check label="テクスチャのコンソール" name="Texture Console"/> + <menu_item_check label="デバッグコンソール" name="Debug Console"/> + <menu_item_check label="ファーストタイマー" name="Fast Timers"/> + <menu_item_separator label="-----------" name="separator"/> <menu_item_call label="通知コンソール" name="Notifications Console"/> + <menu_item_separator label="-----------" name="separator2"/> <menu_item_call label="リージョン情報をデバッグコンソールへ" name="Region Info to Debug Console"/> + <menu_item_call label="グループ情報をデバッグコンソールへ" name="Group Info to Debug Console"/> + <menu_item_call label="性能情報をデバッグコンソールへ" name="Capabilities Info to Debug Console"/> + </menu> + <menu label="HUD情報" name="HUD Info"> + <menu_item_check label="速度" name="Velocity"/> + <menu_item_check label="カメラ" name="Camera"/> + <menu_item_check label="風" name="Wind"/> + <menu_item_check label="FOV (視野角)" name="FOV"/> + </menu> + <menu_item_separator label="-----------" name="separator"/> + <menu_item_call label="ここにすわる" name="Ground Sit"/> + <menu_item_call label="地上にテレポート" name="Teleport to Ground"/> + <menu_item_check label="アバターをファントムにする" name="Phantom"/> + <menu_item_check label="アニメーション・リスト" name="Animation List"/> + <menu_item_check label="このエリアのオブジェクトを検索" name="Area Object Search"/> + <menu_item_check label="テクスチャ・ブラウザ" name="asset browser"/> + <menu_item_separator label="-----------" name="separator2"/> + <menu label="レンダリング" name="Rendering"> + <menu label="種類" name="Types"> + <menu_item_check label="シンプル" name="Simple"/> + <menu_item_check label="アルファ" name="Alpha"/> + <menu_item_check label="木" name="Tree"/> + <menu_item_check label="アバター" name="Character"/> + <menu_item_check label="地表" name="SurfacePatch"/> + <menu_item_check label="空" name="Sky"/> + <menu_item_check label="水" name="Water"/> + <menu_item_check label="地面" name="Ground"/> + <menu_item_check label="ボリューム" name="Volume"/> + <menu_item_check label="草" name="Grass"/> + <menu_item_check label="雲" name="Clouds"/> + <menu_item_check label="パーティクル" name="Particles"/> + <menu_item_check label="衝突" name="Bump"/> + </menu> + <menu label="機能" name="Features"> + <menu_item_check label="UI" name="UI"/> + <menu_item_check label="選択済" name="Selected"/> + <menu_item_check label="ハイライト" name="Highlighted"/> + <menu_item_check label="ダイナミックテクスチャ" name="Dynamic Textures"/> + <menu_item_check label="足の影" name="Foot Shadows"/> + <menu_item_check label="くもり" name="Fog"/> + <menu_item_check label="FRInfo のテスト" name="Test FRInfo"/> + <menu_item_check label="フレキシブルオブジェクト" name="Flexible Objects"/> + </menu> + <menu label="情報を表示" name="Info Displays"> + <menu_item_check label="検証" name="Verify"/> + <menu_item_check label="バウンディングボックス" name="BBoxes"/> + <menu_item_check label="先端" name="Points"/> + <menu_item_check label="オクトリー" name="Octree"/> + <menu_item_check label="オクルージョン" name="Occlusion"/> + <menu_item_check label="バッチの描画" name="Render Batches"/> + <menu_item_check label="アニメーション・テクスチャ" name="Animated Textures"/> + <menu_item_check label="テクスチャ優先度" name="Texture Priority"/> + <menu_item_check label="アバターのレンダリングコストを表示する" name="Avatar Rendering Cost"/> + <menu_item_check label="テクスチャの範囲" name="Texture Area (sqrt(A))"/> + <menu_item_check label="側面" name="Face Area (sqrt(A))"/> + <menu_item_check label="光" name="Lights"/> + <menu_item_check label="パーティクル" name="Particles"/> + </menu> + <menu label="レンダーテスト" name="Render Tests"> + <menu_item_check label="カメラオフセット" name="Camera Offset"/> + <menu_item_check label="フレームレートをランダム化" name="Randomize Framerate"/> + <menu_item_check label="定期的に遅いフレームを挿入する" name="Periodic Slow Frame"/> + <menu_item_check label="フレームテスト" name="Frame Test"/> + </menu> + <menu_item_separator label="-----------" name="separator"/> + <menu_item_check label="軸" name="Axes"/> + <menu_item_separator label="-----------" name="separator2"/> + <menu_item_check label="選択したものを非表示にする" name="Hide Selected"/> + <menu_item_separator label="-----------" name="separator3"/> + <menu_item_check label="接線基底" name="Tangent Basis"/> + <menu_item_call label="選択したテクスチャ情報" name="Selected Texture Info"/> + <menu_item_check label="ワイヤーフレーム" name="Wireframe"/> + <menu_item_check label="オブジェクト間オクルージョン" name="Object-Object Occlusion"/> + <menu_item_check label="GL デバッグ" name="Debug GL"/> + <menu_item_check label="経路をデバッグ" name="Debug Pipeline"/> + <menu_item_check label="ファーストアルファ" name="Fast Alpha"/> + <menu_item_check label="木のアニメーション" name="Animate Trees"/> + <menu_item_check label="テクスチャのアニメーション" name="Animate Textures"/> + <menu_item_check label="テクスチャを無効にする" name="Disable Textures"/> + <menu_item_check label="マルチスレッド処理" name="Run Multiple Threads"/> + <menu_item_check label="チージービーコン" name="Cheesy Beacon"/> + <menu_item_check label="装着された光源を描画する" name="Attached Lights"/> + <menu_item_check label="装着されたパーティクルを描画する" name="Attached Particles"/> + </menu> + <menu label="世界" name="World"> + <menu_item_check label="シムの太陽の設定を無視する" name="Sim Sun Override"/> + <menu_item_call label="スクリプト付きカメラをダンプ" name="Dump Scripted Camera"/> + <menu_item_check label="固定された天気" name="Fixed Weather"/> + <menu_item_call label="リージョンオブジェクトのキャッシュをダンプする" name="Dump Region Object Cache"/> + </menu> + <menu label="RLVa" name="RLVa"> + <menu label="デバッグ" name="Debug"> + <menu_item_check label="デバッグ・メッセージを表示" name="Show Debug Messages"/> + <menu_item_separator label="-----------" name="separator"/> + <menu_item_check label="古い名称を有効にする" name="Enable Legacy Naming"/> + </menu> + <menu_item_separator label="-----------" name="separator"/> + <menu_item_check label="装着を有効にする" name="Enable Wear"/> + <menu_item_separator label="-----------" name="separator2"/> + <menu_item_check label="ロックされたレイヤーを非表示" name="Hide locked layers"/> + <menu_item_check label="ロックされたアタッチメントを非表示" name="Hide locked attachments"/> + <menu_item_separator label="-----------" name="separator3"/> + <menu_item_check label="#RLVフォルダの共有を禁止" name="Forbid Give to #RLV"/> + <menu_item_check label="タグを表示" name="Show Name Tags"/> + <menu_item_separator label="-----------" name="separator4"/> + <menu_item_call label="制限..." name="Restrictions..."/> + </menu> + <menu label="UI" name="UI"> + <menu_item_check label="デフォルトのカラー・ピッカーを使用する" name="Use default system color picker"/> + <menu_item_check label="メニュー・バーに検索ボックスを表示" name="Show search panel in overlay bar"/> + <menu_item_separator label="-----------" name="separator"/> + <menu_item_call label="Web ブラウザのテスト" name="Web Browser Test"/> + <menu_item_call label="UIを編集可能にする" name="Editable UI"/> + <menu_item_call label="SelectMgrをダンプ" name="Dump SelectMgr"/> + <menu_item_call label="持ち物の出力" name="Dump Inventory"/> + <menu_item_call label="フォーカスホールダーをダンプ" name="Dump Focus Holder"/> + <menu_item_call label="選択したオブジェクト情報をプリント" name="Print Selected Object Info"/> + <menu_item_call label="エージェント情報をプリント" name="Print Agent Info"/> + <menu_item_call label="メモリ使用状況" name="Memory Stats"/> + <menu_item_call label="グループ情報のキャッシュをクリア" name="Clear Cached Group Info"/> + <menu_item_separator label="-----------" name="separator2"/> + <menu_item_check label="SelectMgr のデバッグ" name="Debug SelectMgr"/> + <menu_item_check label="ダブルクリック" name="Debug Clicks"/> + <menu_item_check label="表示のデバッグ" name="Debug Views"/> + <menu_item_check label="名称ツールチップのデバッグ" name="Show Name Tooltips"/> + <menu_item_check label="マウス操作によるイベントのデバッグ" name="Debug Mouse Events"/> + <menu_item_check label="キーのデバッグ" name="Debug Keys"/> + <menu_item_check label="WindowProcのデバッグ" name="Debug WindowProc"/> + <menu_item_check label="テキスト・エディタのヒントをデバッグ" name="Debug Text Editor Tips"/> + <menu_item_separator label="-----------" name="separator3"/> + <menu_item_check label="時間を表示する" name="Show Time"/> + <menu_item_check label="描画情報を表示する" name="Show Render Info"/> + <menu_item_check label="マトリックスを表示する" name="Show Matrices"/> + <menu_item_check label="カーソルを乗せた場所の色を表示する" name="Show Color Under Cursor"/> + </menu> + <menu label="XUI" name="XUI"> + <menu_item_call label="ウィンドウのテスト" name="Floater Test"/> + <menu_item_call label="フォントのテスト" name="Font Test"/> + <menu_item_call label="メニューをXMLで書き出し..." name="Export Menus to XML..."/> + <menu_item_call label="UIの編集..." name="Edit UI..."/> + <menu_item_call label="XMLから読み込む" name="Load from XML..."/> + <menu_item_call label="XMLで保存する" name="Save to XML..."/> + <menu_item_check label="XUIネームを表示する" name="Show XUI Names"/> + <menu_item_call label="テスト用 IM を送信する" name="Send Test IMs"/> + </menu> + <menu label="アバター" name="Character"> + <menu label="ベークドテクスチャを取得する" name="Grab Baked Texture"> + <menu_item_call label="瞳" name="Iris"/> + <menu_item_call label="頭" name="Head"/> + <menu_item_call label="上半身" name="Upper Body"/> + <menu_item_call label="下半身" name="Lower Body"/> + <menu_item_call label="スカート" name="Skirt"/> + </menu> + <menu label="キャラクターテスト" name="Character Tests"> + <menu_item_call label="容姿を XML に保存する" name="Appearance To XML"/> + <menu_item_call label="キャラクタジオメトリの切り替え" name="Toggle Character Geometry"/> + <menu_item_call label="男性アバターのテスト" name="Test Male"/> + <menu_item_call label="女性アバターのテスト" name="Test Female"/> + <menu_item_call label="PGを有効にする" name="Toggle PG"/> + <menu_item_check label="アバターの選択を許可" name="Allow Select Avatar"/> + </menu> + <menu_item_check label="ボイスに合わせて唇を動かす" name="Enable Lip Sync (Beta)"/> + <menu_item_check label="矢印キーのTap-Tap-Holdで走る" name="Tap-Tap-Hold To Run"/> + <menu_item_call label="パラメータを強制的にデフォルトにする" name="Force Params to Default"/> + <menu_item_call label="頂点シェーダの再読込" name="Reload Vertex Shader"/> + <menu_item_check label="アニメーション情報" name="Animation Info"/> + <menu_item_check label="スローモーションのアニメーション" name="Slow Motion Animations"/> + <menu_item_check label="見ているものを表示する" name="Show Look At"/> + <menu_item_check label="クリックした場所を表示する" name="Show Point At"/> + <menu_item_check label="見ているものを自分にだけ表示" name="Private Look At"/> + <menu_item_check label="クリックした場所を自分にだけ表示" name="Private Point At"/> + <menu_item_check label="結合部のアップデートのデバッグ" name="Debug Joint Updates"/> + <menu_item_check label="LOD を無効にする" name="Disable LOD"/> + <menu_item_check label="キャラクターVis のデバッグ" name="Debug Character Vis"/> + <menu_item_check label="骨組みの衝突判定を表示する" name="Show Collision Skeleton"/> + <menu_item_check label="エージェントのターゲットを表示する" name="Display Agent Target"/> + <menu_item_check label="回転をデバッグ" name="Debug Rotation"/> + <menu_item_call label="アタッチメントをダンプ" name="Dump Attachments"/> + </menu> + <menu label="クラッシュ" name="Crash"> + <menu_item_call label="バッドメモリアクセスを実行する" name="Force Bad Memory Access"/> + <menu_item_call label="LLErrorとクラッシュを実行する" name="Force LLError And Crash"/> + <menu_item_call label="無限ループ" name="Force Infinite Loop"/> + <menu_item_call label="ドライバのクラッシュを実行する" name="Force Driver Crash"/> + <menu_item_call label="ビューワの接続遮断を実行する" name="Force Disconnect Viewer"/> + <menu_item_separator label="-----------" name="separator"/> + <menu_item_check label="デバッグ用のミニダンプを出力する" name="Output Debug Minidump"/> + </menu> + <menu label="ネットワーク" name="Network"> + <menu_item_call label="メッセージログを有効にする" name="Enable Message Log"/> + <menu_item_call label="メッセージログを使用不可にする" name="Disable Message Log"/> + <menu_item_separator label="-----------" name="separator"/> + <menu_item_check label="速力が挿入されたオブジェクト" name="Velocity Interpolate Objects"/> + <menu_item_check label="挿入されたオブジェクトの位置の Ping" name="Ping Interpolate Object Positions"/> + <menu_item_separator label="-----------" name="separator2"/> + <menu_item_call label="パケットドロップ" name="Drop a Packet"/> + </menu> + <menu label="レコーダー" name="Recorder"> + <menu_item_call label="全セッションのログを記録" name="Full Session Logging"/> + <menu_item_call label="ログの記録開始" name="Start Logging"/> + <menu_item_call label="ログの記録停止" name="Stop Logging"/> + <menu_item_call label="10秒間ログを記録" name="Log 10 Seconds"/> + <menu_item_call label="30秒間ログを記録" name="Log 30 Seconds"/> + <menu_item_call label="60秒間ログを記録" name="Log 60 Seconds"/> + <menu_item_separator label="-----------" name="separator"/> + <menu_item_call label="再生開始" name="Start Playback"/> + <menu_item_call label="再生停止" name="Stop Playback"/> + <menu_item_check label="再生をループ" name="Loop Playback"/> + <menu_item_call label="記録開始" name="Start Record"/> + <menu_item_call label="記録停止" name="Stop Record"/> + </menu> + <menu label="管理者オプション" name="Admin Options"> + <menu_item_check label="管理者メニューを表示する" name="View Admin Options"/> + <menu_item_call label="管理者ステータスの呼び出し" name="Request Admin Status"/> + <menu_item_call label="管理者ステータス解除" name="Leave Admin Status"/> + </menu> + <menu_item_separator label="-----------" name="separator3"/> + <menu_item_check label="オブジェクトのアップデートを表示する" name="Show Updates"/> + <menu_item_separator label="-----------" name="separator4"/> + <menu_item_check label="シャッター音とアニメーションなしでスナップショットをディスクに保存する" name="Quiet Snapshots to Disk"/> + <menu_item_call label="画像を圧縮" name="Compress Image..."/> + <menu_item_check label="ビルドの最大制限を解除" name="Disable Max Build Constraints"/> + <menu_item_check label="権限の詳細を表示する" name="Debug Permissions"/> + <menu_item_check label="マウスの動きをスムーズに" name="Mouse Smoothing"/> + <menu_item_check label="マウスルック時に十字カーソルを表示" name="Show Mouselook Crosshairs"/> + <menu_item_separator label="-----------" name="separator5"/> + <menu_item_check label="次回の起動時にコンソールウィンドウを表示する" name="Console Window"/> + <menu_item_check label="Restrained Loveの使用" name="Restrained Love Support"/> + <menu_item_check label="複数のImprudenceの同時起動を許可" name="Allow Multiple Instances"/> + <menu_item_call label="ログアウト" name="Logout"/> + <menu_item_call label="デバッグ設定を表示する" name="Debug Settings"/> </menu> + + </menu_bar> diff --git a/linden/indra/newview/skins/default/xui/ja/notifications.xml b/linden/indra/newview/skins/default/xui/ja/notifications.xml index 77c60689e..6da6cccc1 100644 --- a/linden/indra/newview/skins/default/xui/ja/notifications.xml +++ b/linden/indra/newview/skins/default/xui/ja/notifications.xml @@ -3271,6 +3271,30 @@ Macの場合は、Cmd-Opt-Shift-Dを押してください。 <notification name="UnableToOpenCommandURL"> クリックしたURLはこのウェブブラウザでは開けません </notification> + + +<!-- ここから Imprudence 固有の通知 --> + + + <notification name="ConfirmAutoPilot"> + 本当にここまで歩きますか? + <usetemplate ignoretext="オートパイロットする時" name="okcancelignore" notext="キャンセル" yestext="歩く"/> + </notification> + + <notification name="ConfirmDoubleClickTP"> + 本当にここにテレポートしますか? + <usetemplate ignoretext="ダブルクリックテレポート時" name="okcancelignore" notext="キャンセル" yestext="テレポート"/> + </notification> + + <notification name="ConfirmTeleportHome"> + 本当にホームにテレポートしますか? + <usetemplate ignoretext="ホームにテレポートする時" name="okcancelignore" notext="キャンセル" yestext="テレポート"/> + </notification> + + +<!-- ここまで Imprudence 固有の通知 --> + + <global name="UnsupportedCPU"> - あなたの CPU の速度は必須動作環境の条件を満たしていません。 </global> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_avatar.xml b/linden/indra/newview/skins/default/xui/ja/panel_avatar.xml index a3745a274..147a5f6b5 100644 --- a/linden/indra/newview/skins/default/xui/ja/panel_avatar.xml +++ b/linden/indra/newview/skins/default/xui/ja/panel_avatar.xml @@ -60,6 +60,7 @@ <text name="Photo:"> 写真: </text> + <button label="UUIDコピー" name="btn_copy_uuid"/> <texture_picker label="" name="img" tool_tip="写真をクリックして選択"/> <text name="Groups:"> グループ: @@ -77,8 +78,11 @@ </text> <view_border name="drop_target_rect" /> <view_border name="drop_target_rect_vis" /> - <text name="Give inventory" tool_tip="ここに物品目をドロップしてこの人に贈ります"> - 持ち物アイテムをここにドロップします + <text name="drop target" tool_tip="ここに持ち物アイテムをドロップしてこの人に贈ります"> + 持ち物アイテムを + </text> + <text name="Give inventory 2" tool_tip="ここに持ち物アイテムをドロップしてこの人に贈ります"> + ここにドロップします </text> <check_box label="検索に表示" name="allow_publish" tool_tip="検索で、詳細やイメージなどさらなるプロフィール情報を公開する。"/> <button label="?" label_selected="?" name="?"/> @@ -87,6 +91,7 @@ <button label="フレンドに追加" label_selected="フレンドに追加" name="Add Friend..." /> <button label="支払う" label_selected="支払う" name="Pay..."/> <button label="IMを送る" label_selected="IMを送る" name="Instant Message..." tool_tip="インスタント・メッセージ (IM)" /> + <button label="グループに招待..." label_selected="グループに招待" name="Invite to Group..." /> <button label="無視する" label_selected="無視する" name="Mute" /> </panel> <panel label="ウェブ" name="WebProfile"> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_groups.xml b/linden/indra/newview/skins/default/xui/ja/panel_groups.xml index adfdcd49c..f326a1373 100644 --- a/linden/indra/newview/skins/default/xui/ja/panel_groups.xml +++ b/linden/indra/newview/skins/default/xui/ja/panel_groups.xml @@ -13,6 +13,8 @@ <button label="抜ける" name="Leave" /> <button label="作成..." name="Create" /> <button label="検索..." name="Search..." /> + <button label="招待..." name="Invite..." /> + <button label="タイトル..." name="Titles..." /> <string name="none"> グループなし </string> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_mini_map.xml b/linden/indra/newview/skins/default/xui/ja/panel_mini_map.xml index fdc4465c9..2f0711627 100644 --- a/linden/indra/newview/skins/default/xui/ja/panel_mini_map.xml +++ b/linden/indra/newview/skins/default/xui/ja/panel_mini_map.xml @@ -24,4 +24,15 @@ <text name="nw_label" width="40"> 北西 </text> + + <string name="tooltip_tp"> + ダブルクリックでテレポートします + </string> + <string name="tooltip_pan"> + Shift+ドラッグでパンします + </string> + <string name="tooltip_map"> + ダブルクリックで地図を開きます + </string> + </panel> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_preferences_advanced.xml b/linden/indra/newview/skins/default/xui/ja/panel_preferences_advanced.xml index ef13a7500..4b5a2bb0f 100644 --- a/linden/indra/newview/skins/default/xui/ja/panel_preferences_advanced.xml +++ b/linden/indra/newview/skins/default/xui/ja/panel_preferences_advanced.xml @@ -1,4 +1,33 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<panel name="advanced_panel"> +<panel label="高度な設定" name="advanced_panel"> + <check_box label="ログイン/ログアウト画面を非表示" name="disable_log_screen_check"/> + <check_box label="テレポート画面を非表示" name="disable_tp_screen_check"/> + <check_box label="名前タグに使用ビューワの名称を表示" name="client_name_tag_check"/> + <check_box label="ビューワを色で識別" name="client_name_color_check"/> + <check_box label="ビューワの名称にヒントを表示" name="client_name_hover_check"/> + <check_box label="自分のビューワ名称をタグに表示" name="client_name_tag_broadcast_check"/> + <check_box label="影を有効にする(警告:動作が不安定になり、高いグラフィック性能が必要です。)" name="shadows_check"/> + <text bottom_delta="-25" left="16" height="15" width="300" + follows="top|left"> + LightShare機能の使用(OpenSimのみ): + </text> + <combo_box name="lightshare_combo"> + <combo_item name="never"> + 使用しない + </combo_item> + <combo_item name="ask"> + 毎回確認 + </combo_item> + <combo_item name="always"> + 常に使用 + </combo_item> + </combo_box> + <check_box label="HTTPテクスチャを使用(試験中の機能)" name="http_texture_check"/> + <check_box label="遠距離の描画をスキップして早く読み込む" name="speed_rez_check"/> + <check_box label="容姿編集中のアニメーションを表示" name="appearance_anim_check"/> + <check_box label="伝統的なパイメニューを使用" name="legacy_pie_menu_checkbox"/> <check_box label="言語をオブジェクトと共有" name="language_is_public" tool_tip="優先言語をインワールドのオブジェクトが認識する"/> + <check_box label="チャットとIMで MU* ポーズ・スタイルを使用" name="allow_mupose"/> + <check_box label="OOCチャットの自動クローズ" name="auto_close_ooc"/> + <button label="全ての設定を初期値に戻す" name="reset_btn"/> </panel> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_preferences_audio.xml b/linden/indra/newview/skins/default/xui/ja/panel_preferences_audio.xml index 9a8d1757a..c617ba18a 100644 --- a/linden/indra/newview/skins/default/xui/ja/panel_preferences_audio.xml +++ b/linden/indra/newview/skins/default/xui/ja/panel_preferences_audio.xml @@ -20,6 +20,7 @@ </text> <check_box label="音楽がある場合再生する(通信が重くなる)" name="streaming_music" /> + <check_box label="音楽のタイトルをチャットに表示" name="show_stream_title"/> <check_box label="ストリーミング・メディア使用可時に再生(帯域幅の消費増)" name="streaming_video" /> @@ -35,11 +36,15 @@ <text type="string" length="1" name="ui_volume_text"> UI音量: </text> + <text name="ambient_prefs_text"> + 環境音: + </text> + <check_box label="風の発生を有効にする" name="mute_wind_check"/> <slider label="ドップラー効果" name="Doppler Effect" /> <slider label="遠隔要因" name="Distance Factor" /> <slider label="ロールオフ係数" name="Rolloff Factor" /> <spinner label="L$変更基準点" name="L$ Change Threshold" /> - <spinner label="ヘルス変化基準点" name="Health Change Threshold" /> + <spinner label="ヘルス変化基準点" name="Health change threshold" /> <text type="string" length="1" name="doppler_effect_text"> オーディオ環境設定: </text> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_preferences_fonts.xml b/linden/indra/newview/skins/default/xui/ja/panel_preferences_fonts.xml new file mode 100644 index 000000000..3cf54b7fa --- /dev/null +++ b/linden/indra/newview/skins/default/xui/ja/panel_preferences_fonts.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> + +<panel label="フォント" name="font_panel"> + + <text> + ユーザー・インターフェースのフォントを変更できます。(再起動後に有効) + </text> + +</panel> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_preferences_general.xml b/linden/indra/newview/skins/default/xui/ja/panel_preferences_general.xml index 83b21b87d..ee9937323 100644 --- a/linden/indra/newview/skins/default/xui/ja/panel_preferences_general.xml +++ b/linden/indra/newview/skins/default/xui/ja/panel_preferences_general.xml @@ -32,8 +32,16 @@ UI サイズ: </text> <check_box label="解像度独立スケールを使用" name="ui_auto_scale"/> + <check_box label="操作していない時は退席/AFK" name="afk_timeout_checkbox"/> <spinner label="退席までの時間:" name="afk_timeout_spinner"/> + <!-- リンデン・ドル支払/受取の通知は「ポップアップ」タブへ移動 <check_box label="リンデン・ドル(L$)の支払い/受け取りを通知" name="notify_money_change_checkbox"/> + --> + <text name="Mini-Map Notify:"> + ミニマップ通知: + </text> + <check_box label="チャット範囲に入った時" name="mini_map_notify_chat"/> + <check_box label="SIMに入った時" name="mini_map_notify_sim"/> <text name="maturity_desired_label"> レーティング区分: </text> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml b/linden/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml index 167bc2a1c..bca61d9b7 100644 --- a/linden/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml +++ b/linden/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml @@ -5,6 +5,7 @@ </text> <button label="?" name="GraphicsPreferencesHelpButton" /> <check_box label="ウィンドウ内で Second Life を起動" name="windowed mode" /> + <check_box label="Windlightツールバーを表示" name="toggle_windlight_control"/> <text_editor name="voice_chat_description"> チェック無しの場合は、ログイン時にフルスクリーン表示 </text_editor> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_preferences_im.xml b/linden/indra/newview/skins/default/xui/ja/panel_preferences_im.xml index a2c13bb5d..8d4a56451 100644 --- a/linden/indra/newview/skins/default/xui/ja/panel_preferences_im.xml +++ b/linden/indra/newview/skins/default/xui/ja/panel_preferences_im.xml @@ -11,9 +11,14 @@ ログインして変更してください </text> <check_box label="IMを電子メール([EMAIL])へ送信" name="send_im_to_email"/> - <check_box label="チャットコンソールにIMを表示する" name="include_im_in_chat_console"/> + <text name="show_ims_label"> + IMの表示: + </text> + <check_box label="チャットコンソールに表示" name="include_im_in_chat_console" left="208"/> + <check_box label="チャット履歴に表示" name="include_im_in_chat_history" left="358"/> <check_box label="IMにタイムスタンプを表示" name="show_timestamps_check"/> <check_box label="オンライン・フレンド通知を表示" name="friends_online_notify_checkbox"/> + <check_box label="IMタブを縦並びに(再起動後に有効)" name="vertical-imtabs-toggle"/> <text name="text_box4"> 記録オプション: </text> @@ -29,4 +34,5 @@ 取り込み中 応答メッセージ: </text> + <button label="IM応答オプション" name="busy_adv_btn"/> </panel> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_preferences_input.xml b/linden/indra/newview/skins/default/xui/ja/panel_preferences_input.xml index ded6f9df3..ed20af239 100644 --- a/linden/indra/newview/skins/default/xui/ja/panel_preferences_input.xml +++ b/linden/indra/newview/skins/default/xui/ja/panel_preferences_input.xml @@ -21,11 +21,42 @@ <text name="Camera Follow Distance:"> カメラ追従距離: </text> + <text name="Camera Transition Time:"> + カメラ切替時間: + </text> + <text name="Camera Smoothing:"> + カメラの滑らかさ: + </text> + <check_box label="編集カメラの自動移動" name="edit_camera_movement" tool_tip="編集モードの開始、終了時はカメラ自動位置調整を使用"/> <check_box label="容姿カメラの自動移動" name="appearance_camera_movement" tool_tip="編集モードでは、カメラ自動位置調整を使用"/> + <check_box label="カメラ移動の制限を解除" name="Disable camera constraints"/> + <check_box label="ズームの最短距離制限を解除" name="disable_min_zoom_check"/> <text name="text2"> アバター表示: </text> <check_box label="アバターを一人称視点(マウスルック)で表示" name="first_person_avatar_visible"/> <button label="ジョイスティック設定" name="joystick_setup_button"/> + <text name="double_click_action_label"> + ダブルクリック時の動作: + </text> + <combo_box name="double_click_action"> + <combo_item name="None"> + なし + </combo_item> + <combo_item name="Go"> + オートパイロット + </combo_item> + </combo_box> + <text name="go_action_label"> + オートパイロットの種類: + </text> + <combo_box name="go_action"> + <combo_item name="Move"> + 歩く + </combo_item> + <combo_item name="Teleport"> + テレポート + </combo_item> + </combo_box> </panel> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_preferences_popups.xml b/linden/indra/newview/skins/default/xui/ja/panel_preferences_popups.xml index 9c1ca6edc..75b316c1b 100644 --- a/linden/indra/newview/skins/default/xui/ja/panel_preferences_popups.xml +++ b/linden/indra/newview/skins/default/xui/ja/panel_preferences_popups.xml @@ -18,4 +18,5 @@ <button width="235" label="ポップアップ全てを有効化..." label_selected="「次回表示」ダイアログリセット..." name="reset_dialogs_btn" tool_tip="全てのオプショナルポップアップと「初回使用」通知を有効にしてください。"/> <button width="235" label="これらのポップアップ全てを無効化..." name="skip_dialogs_btn" tool_tip="全てのオプショナルポップアップと「初回使用」通知を無効にしてください。"/> <check_box label="新たに受け取ったオブジェクトを持ち物に自動的に表示" name="show_in_inventory"/> + <check_box label="[CURRENCY]を使用・受け取る時に通知" name="notify_money_change_checkbox"/> </panel> diff --git a/linden/indra/newview/skins/default/xui/ja/panel_radar.xml b/linden/indra/newview/skins/default/xui/ja/panel_radar.xml new file mode 100644 index 000000000..ae86ae641 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/ja/panel_radar.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> + +<!-- Note: panel rect (size) is specified in floater_mini_map.xml --> + +<panel name="RadarPanel" label="レーダー"> + + <string name="no_one_near"> + 近くに誰もいません + </string> + <string name="is_muted"> + (ミュート) + </string> + <string name="is_typing"> + (タイプ中) + </string> + <string name="entering_chat_range"> + [NAME] さんがチャットレンジに入ってきました。 ([DISTANCE]m) + </string> + <string name="entering_sim_range"> + [NAME] さんがSIMに入ってきました。 ([DISTANCE]m) + </string> + <string name="avatars_in_singular"> + [COUNT]人のアバター + </string> + <string name="avatars_in_plural"> + [COUNT]人のアバター + </string> + <string name="unknown_avatar"> + (不明) + </string> + + <tab_container name="radar_tab_container"> + <panel name="avatar_tab" label="アバター"> + <button name="im_btn" label="IM/コール" tool_tip="IMウィンドウを開きます" /> + <button name="profile_btn" label="プロフィール" tool_tip="写真、所属グループ、その他の情報"/> + <button name="offer_teleport_btn" label="TPを送る" tool_tip="この人にテレポートを送って自分のところに呼びます"/> + <button name="teleport_btn" label="居場所へTP" tool_tip="この人のいるところにテレポートします"/> + <button name="track_btn" label="追跡する" tool_tip="地図上のフレンドにビーコンを作成、追跡します"/> + <button name="invite_btn" label="招待..." tool_tip="この人を自分の所属グループに招待します"/> + <button name="add_btn" label="追加..." tool_tip="この人にフレンド要請を送ります"/> + </panel> + <panel name="estate_tab" label="不動産管理"> + <button name="cam_btn" label="カメラ追跡"/> + <button name="freeze_btn" label="動けなくする..."/> + <button name="eject_btn" label="追い出す..."/> + <button name="ban_btn" label="立入禁止..."/> + <button name="mute_btn" label="ミュート..."/> + <button name="unmute_btn" label="ミュート解除..."/> + <button name="ar_btn" label="報告..."/> + </panel> + </tab_container> + + <scroll_list name="RadarList"> + <column name="avatar_name" label="名前"/> + <column name="avatar_distance" label="距離"/> + </scroll_list> + +</panel> + diff --git a/linden/indra/newview/skins/default/xui/ja/panel_windlight_controls.xml b/linden/indra/newview/skins/default/xui/ja/panel_windlight_controls.xml new file mode 100644 index 000000000..bfe6a423f --- /dev/null +++ b/linden/indra/newview/skins/default/xui/ja/panel_windlight_controls.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel name="windlight_controls"> + <button label="環境編集" name="Environment"/> + <flyout_button label="空" name="Presets"> + </flyout_button> +</panel> diff --git a/linden/indra/newview/skins/default/xui/zh/mime_types.xml b/linden/indra/newview/skins/default/xui/zh/mime_types.xml index fc5fae414..0cc6f2f23 100644 --- a/linden/indra/newview/skins/default/xui/zh/mime_types.xml +++ b/linden/indra/newview/skins/default/xui/zh/mime_types.xml @@ -1,14 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <mimetypes name="default"> - <defaultlabel> - (未知) - </defaultlabel> - <defaultwidget> - 无 - </defaultwidget> - <defaultimpl> - LLMediaImplLLMozLib - </defaultimpl> <widgetset name="web"> <label name="web_label"> 网页内容 diff --git a/linden/indra/newview/viewer_manifest.py b/linden/indra/newview/viewer_manifest.py index ff59aec75..56c241048 100755 --- a/linden/indra/newview/viewer_manifest.py +++ b/linden/indra/newview/viewer_manifest.py @@ -162,6 +162,8 @@ def login_channel(self): def standalone(self): return self.args['standalone'] == "ON" + def debug(self): + return self.args['buildtype'] == "DEBUG" def grid(self): return self.args['grid'] def channel(self): @@ -228,9 +230,15 @@ def construct(self): self.path("LICENSE-libraries.txt") self.end_prefix("../..") - + self.path("imprudence.url") + # Plugin host application + self.path(os.path.join(os.pardir, + 'llplugin', 'slplugin', self.args['configuration'], "SLPlugin.exe"), + "SLPlugin.exe") + + self.path("featuretable.txt") # For use in crash reporting (generates minidumps) @@ -240,7 +248,17 @@ def construct(self): #self.path("fmod.dll") # For spellchecking - self.path("libhunspell.dll") + if self.prefix(src=self.args['configuration'], dst=""): + self.path("libhunspell.dll") + self.end_prefix() + + # Get llcommon and deps. + if self.prefix(src=self.args['configuration'], dst=""): + self.path('libapr-1.dll') + self.path('libaprutil-1.dll') + self.path('libapriconv-1.dll') + self.path('llcommon.dll') + self.end_prefix() # For textures if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): @@ -253,7 +271,41 @@ def construct(self): self.path("alut.dll") self.end_prefix() - # Mozilla appears to force a dependency on these files so we need to ship it (CP) - updated to vc8 versions (nyx) + # Media plugins - QuickTime + if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): + self.path("media_plugin_quicktime.dll") + self.end_prefix() + + # Media plugins - WebKit/Qt + if self.prefix(src='../media_plugins/webkit/%s' % self.args['configuration'], dst="llplugin"): + self.path("media_plugin_webkit.dll") + self.end_prefix() + + # For WebKit/Qt plugin runtimes + if self.prefix(src="../../libraries/i686-win32/lib/release", dst="llplugin"): + self.path("libeay32.dll") + self.path("qtcore4.dll") + self.path("qtgui4.dll") + self.path("qtnetwork4.dll") + self.path("qtopengl4.dll") + self.path("qtwebkit4.dll") + self.path("qtxmlpatterns4.dll") + self.path("ssleay32.dll") + self.end_prefix() + + # For WebKit/Qt plugin runtimes (image format plugins) + if self.prefix(src="../../libraries/i686-win32/lib/release/imageformats", dst="llplugin/imageformats"): + self.path("qgif4.dll") + self.path("qico4.dll") + self.path("qjpeg4.dll") + self.path("qmng4.dll") + self.path("qsvg4.dll") + self.path("qtiff4.dll") + self.end_prefix() + + # Per platform MIME config on the cheap. See SNOW-307 / DEV-41388 + self.path("skins/default/xui/en-us/mime_types_windows.xml", "skins/default/xui/en-us/mime_types.xml") + # These need to be installed as a SxS assembly, currently a 'private' assembly. # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx if self.prefix(src=self.args['configuration'], dst=""): @@ -280,34 +332,6 @@ def construct(self): # same thing for auto-updater. #self.path(src="%s/imprudence-bin.exe.config" % self.args['configuration'], dst="updater.exe.config") - # Mozilla runtime DLLs (CP) - if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - self.path("freebl3.dll") - self.path("js3250.dll") - self.path("nspr4.dll") - self.path("nss3.dll") - self.path("nssckbi.dll") - self.path("plc4.dll") - self.path("plds4.dll") - self.path("smime3.dll") - self.path("softokn3.dll") - self.path("ssl3.dll") - self.path("xpcom.dll") - self.path("xul.dll") - self.end_prefix() - - # Mozilla runtime misc files (CP) - if self.prefix(src="app_settings/mozilla"): - self.path("chrome/*.*") - self.path("components/*.*") - self.path("greprefs/*.*") - self.path("plugins/*.*") - self.path("res/*.*") - self.path("res/*/*") - self.end_prefix() - - # Mozilla hack to get it to accept newer versions of msvc*80.dll than are listed in manifest - # necessary as llmozlib2-vc80.lib refers to an old version of msvc*80.dll - can be removed when new version of llmozlib is built - Nyx # Vivox runtimes if self.prefix(src="vivox-runtime/i686-win32", dst=""): # self.path("alut.dll") @@ -322,63 +346,64 @@ def construct(self): self.path("ortp.dll") self.end_prefix() - +# Gstreamer is not used in webkit_plugins. The librries are never delivered/extracted to +# ../../libraries/i686-win32/lib/release . Commented out until decision made to use or drop. # Gstreamer plugins - if self.prefix(src="lib/gstreamer-plugins", dst=""): - self.path("*.dll", dst="lib/gstreamer-plugins/*.dll") - self.end_prefix() + #if self.prefix(src="lib/gstreamer-plugins", dst=""): + # self.path("*.dll", dst="lib/gstreamer-plugins/*.dll") + # self.end_prefix() # Gstreamer libs - if (not self.standalone()) and self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): - self.path("iconv.dll") - self.path("libxml2.dll") - self.path("libcairo-2.dll") - self.path("libgio-2.0-0.dll") - self.path("libglib-2.0-0.dll") - self.path("libgmodule-2.0-0.dll") - self.path("libgobject-2.0-0.dll") - self.path("libgthread-2.0-0.dll") - self.path("charset.dll") - self.path("intl.dll") - self.path("libgcrypt-11.dll") - self.path("libgnutls-26.dll") - self.path("libgpg-error-0.dll") - self.path("libgstapp.dll") - self.path("libgstaudio.dll") - self.path("libgstbase-0.10.dll") - self.path("libgstcdda.dll") - self.path("libgstcontroller-0.10.dll") - self.path("libgstdataprotocol-0.10.dll") - self.path("libgstdshow.dll") - self.path("libgstfft.dll") - self.path("libgstinterfaces.dll") - self.path("libgstnet-0.10.dll") - self.path("libgstnetbuffer.dll") - self.path("libgstpbutils.dll") - self.path("libgstreamer-0.10.dll") - self.path("libgstriff.dll") - self.path("libgstrtp.dll") - self.path("libgstrtsp.dll") - self.path("libgstsdp.dll") - self.path("libgsttag.dll") - self.path("libgstvideo.dll") - self.path("libjpeg.dll") - self.path("libmp3lame-0.dll") - self.path("libneon-27.dll") - self.path("libogg-0.dll") - self.path("liboil-0.3-0.dll") - self.path("libopenjpeg-2.dll") - self.path("libpng12-0.dll") - self.path("libschroedinger-1.0-0.dll") - self.path("libspeex-1.dll") - self.path("libtheora-0.dll") - self.path("libvorbis-0.dll") - self.path("libvorbisenc-2.dll") - self.path("libxml2-2.dll") - self.path("glew32.dll") - self.path("xvidcore.dll") - self.path("zlib1.dll") - self.end_prefix() + #if (not self.standalone()) and self.prefix(src="../../libraries/i686-win32/lib/release", dst=""): + # self.path("iconv.dll") + # self.path("libxml2.dll") + # self.path("libcairo-2.dll") + # self.path("libgio-2.0-0.dll") + # self.path("libglib-2.0-0.dll") + # self.path("libgmodule-2.0-0.dll") + # self.path("libgobject-2.0-0.dll") + # self.path("libgthread-2.0-0.dll") + # self.path("charset.dll") + # self.path("intl.dll") + # self.path("libgcrypt-11.dll") + # self.path("libgnutls-26.dll") + # self.path("libgpg-error-0.dll") + # self.path("libgstapp.dll") + # self.path("libgstaudio.dll") + # self.path("libgstbase-0.10.dll") + # self.path("libgstcdda.dll") + # self.path("libgstcontroller-0.10.dll") + # self.path("libgstdataprotocol-0.10.dll") + # self.path("libgstdshow.dll") + # self.path("libgstfft.dll") + # self.path("libgstinterfaces.dll") + # self.path("libgstnet-0.10.dll") + # self.path("libgstnetbuffer.dll") + # self.path("libgstpbutils.dll") + # self.path("libgstreamer-0.10.dll") + # self.path("libgstriff.dll") + # self.path("libgstrtp.dll") + # self.path("libgstrtsp.dll") + # self.path("libgstsdp.dll") + # self.path("libgsttag.dll") + # self.path("libgstvideo.dll") + # self.path("libjpeg.dll") + # self.path("libmp3lame-0.dll") + # self.path("libneon-27.dll") + # self.path("libogg-0.dll") + # self.path("liboil-0.3-0.dll") + # self.path("libopenjpeg-2.dll") + # self.path("libpng12-0.dll") + # self.path("libschroedinger-1.0-0.dll") + # self.path("libspeex-1.dll") + # self.path("libtheora-0.dll") + # self.path("libvorbis-0.dll") + # self.path("libvorbisenc-2.dll") + # self.path("libxml2-2.dll") + # self.path("glew32.dll") + # self.path("xvidcore.dll") + # self.path("zlib1.dll") + # self.end_prefix() # # pull in the crash logger and updater from other projects # self.path(src=self.find_existing_file( # tag:"crash-logger" here as a cue to the exporter @@ -540,10 +565,7 @@ def construct(self): self.path(self.args['configuration'] + "/Imprudence.app", dst="") if self.prefix(src="", dst="Contents"): # everything goes in Contents - # Expand the tar file containing the assorted mozilla bits into - # <bundle>/Contents/MacOS/ - self.contents_of_tar(self.args['source']+'/mozilla-universal-darwin.tgz', 'MacOS') - + self.path("Info-Imprudence.plist", dst="Info.plist") # copy additional libs in <bundle>/Contents/MacOS/ @@ -560,28 +582,28 @@ def construct(self): self.path("libgobject-2.0.dylib") self.path("libgthread-2.0.dylib") - self.path("libgstreamer-0.10.dylib") - self.path("libgstapp-0.10.dylib") - self.path("libgstaudio-0.10.dylib") - self.path("libgstbase-0.10.dylib") - self.path("libgstcdda-0.10.dylib") - self.path("libgstcontroller-0.10.dylib") - self.path("libgstdataprotocol-0.10.dylib") - self.path("libgstfft-0.10.dylib") - self.path("libgstinterfaces-0.10.dylib") - self.path("libgstnet-0.10.dylib") - self.path("libgstnetbuffer-0.10.dylib") - self.path("libgstpbutils-0.10.dylib") - self.path("libgstriff-0.10.dylib") - self.path("libgstrtp-0.10.dylib") - self.path("libgstrtsp-0.10.dylib") - self.path("libgstsdp-0.10.dylib") - self.path("libgsttag-0.10.dylib") - self.path("libgstvideo-0.10.dylib") + # self.path("libgstreamer-0.10.dylib") + # self.path("libgstapp-0.10.dylib") + # self.path("libgstaudio-0.10.dylib") + # self.path("libgstbase-0.10.dylib") + # self.path("libgstcdda-0.10.dylib") + # self.path("libgstcontroller-0.10.dylib") + # self.path("libgstdataprotocol-0.10.dylib") + # self.path("libgstfft-0.10.dylib") + # self.path("libgstinterfaces-0.10.dylib") + # self.path("libgstnet-0.10.dylib") + # self.path("libgstnetbuffer-0.10.dylib") + # self.path("libgstpbutils-0.10.dylib") + # self.path("libgstriff-0.10.dylib") + # self.path("libgstrtp-0.10.dylib") + # self.path("libgstrtsp-0.10.dylib") + # self.path("libgstsdp-0.10.dylib") + # self.path("libgsttag-0.10.dylib") + # self.path("libgstvideo-0.10.dylib") self.path("libxml2.2.dylib") - self.path("libfaad.2.dylib") - self.path("libFLAC.8.dylib") + # self.path("libfaad.2.dylib") + # self.path("libFLAC.8.dylib") self.path("libintl.3.dylib") self.path("libjpeg.62.dylib") self.path("libpng12.0.dylib") @@ -589,19 +611,13 @@ def construct(self): self.path("libogg.0.dylib") self.path("liboil-0.3.0.dylib") self.path("libopenjpeg.1.4.dylib") - self.path("libtheora.0.dylib") + # self.path("libtheora.0.dylib") self.path("libvorbis.0.dylib") self.path("libvorbisenc.2.dylib") self.path("libvorbisfile.3.dylib") self.end_prefix("../../libraries/universal-darwin/lib_release") - # replace the default theme with our custom theme (so scrollbars work). - if self.prefix(src="mozilla-theme", dst="MacOS/chrome"): - self.path("classic.jar") - self.path("classic.manifest") - self.end_prefix("MacOS/chrome") - # most everything goes in the Resources directory if self.prefix(src="", dst="Resources"): super(DarwinManifest, self).construct() @@ -641,78 +657,78 @@ def construct(self): self.path("zh-Hans.lproj") - if (not self.standalone()) and self.prefix(src="../../libraries/universal-darwin/lib_release/gstreamer-plugins", dst="lib/gstreamer-plugins"): - self.path("libgstaacparse.so") - self.path("libgstadder.so") - self.path("libgstaiffparse.so") - self.path("libgstamrparse.so") - self.path("libgstapp.so") - self.path("libgstaudioconvert.so") - self.path("libgstaudiorate.so") - self.path("libgstaudioresample.so") - self.path("libgstautodetect.so") - self.path("libgstavi.so") - self.path("libgstcoreelements.so") - self.path("libgstcoreindexers.so") - self.path("libgstdebug.so") - self.path("libgstdecodebin.so") - self.path("libgstdecodebin2.so") - self.path("libgstdeinterlace2.so") - self.path("libgstequalizer.so") - self.path("libgstfaad.so") - self.path("libgstffmpeg.so") - self.path("libgstffmpegcolorspace.so") - self.path("libgstffmpegscale.so") - self.path("libgstfilter.so") - self.path("libgstflac.so") - self.path("libgstflv.so") - self.path("libgstgdp.so") - self.path("libgsth264parse.so") - self.path("libgsticydemux.so") - self.path("libgstid3demux.so") - self.path("libgstinterleave.so") - self.path("libgstjpeg.so") - self.path("libgstlevel.so") - self.path("libgstmetadata.so") - self.path("libgstmpeg4videoparse.so") - self.path("libgstmpegdemux.so") - self.path("libgstmpegvideoparse.so") - self.path("libgstmultifile.so") - self.path("libgstmultipart.so") - self.path("libgstneonhttpsrc.so") - self.path("libgstogg.so") - self.path("libgstosxaudio.so") - self.path("libgstosxvideosink.so") - self.path("libgstplaybin.so") - self.path("libgstpng.so") - self.path("libgstpostproc.so") - self.path("libgstqtdemux.so") - #self.path("libgstqtwrapper.so") - self.path("libgstqueue2.so") - self.path("libgstreal.so") - self.path("libgstrtp.so") - self.path("libgstrtpmanager.so") - self.path("libgstrtsp.so") - self.path("libgstsdpelem.so") - self.path("libgstselector.so") - self.path("libgststereo.so") - self.path("libgsttcp.so") - self.path("libgsttheora.so") - self.path("libgsttypefindfunctions.so") - self.path("libgstudp.so") - self.path("libgstvideobalance.so") - self.path("libgstvideobox.so") - self.path("libgstvideocrop.so") - self.path("libgstvideoflip.so") - self.path("libgstvideomixer.so") - self.path("libgstvideorate.so") - self.path("libgstvideoscale.so") - self.path("libgstvideosignal.so") - self.path("libgstvolume.so") - self.path("libgstvorbis.so") - self.path("libgstwavparse.so") + # if (not self.standalone()) and self.prefix(src="../../libraries/universal-darwin/lib_release/gstreamer-plugins", dst="lib/gstreamer-plugins"): + # self.path("libgstaacparse.so") + # self.path("libgstadder.so") + # self.path("libgstaiffparse.so") + # self.path("libgstamrparse.so") + # self.path("libgstapp.so") + # self.path("libgstaudioconvert.so") + # self.path("libgstaudiorate.so") + # self.path("libgstaudioresample.so") + # self.path("libgstautodetect.so") + # self.path("libgstavi.so") + # self.path("libgstcoreelements.so") + # self.path("libgstcoreindexers.so") + # self.path("libgstdebug.so") + # self.path("libgstdecodebin.so") + # self.path("libgstdecodebin2.so") + # self.path("libgstdeinterlace2.so") + # self.path("libgstequalizer.so") + # self.path("libgstfaad.so") + # self.path("libgstffmpeg.so") + # self.path("libgstffmpegcolorspace.so") + # self.path("libgstffmpegscale.so") + # self.path("libgstfilter.so") + # self.path("libgstflac.so") + # self.path("libgstflv.so") + # self.path("libgstgdp.so") + # self.path("libgsth264parse.so") + # self.path("libgsticydemux.so") + # self.path("libgstid3demux.so") + # self.path("libgstinterleave.so") + # self.path("libgstjpeg.so") + # self.path("libgstlevel.so") + # self.path("libgstmetadata.so") + # self.path("libgstmpeg4videoparse.so") + # self.path("libgstmpegdemux.so") + # self.path("libgstmpegvideoparse.so") + # self.path("libgstmultifile.so") + # self.path("libgstmultipart.so") + # self.path("libgstneonhttpsrc.so") + # self.path("libgstogg.so") + # self.path("libgstosxaudio.so") + # self.path("libgstosxvideosink.so") + # self.path("libgstplaybin.so") + # self.path("libgstpng.so") + # self.path("libgstpostproc.so") + # self.path("libgstqtdemux.so") + # #self.path("libgstqtwrapper.so") + # self.path("libgstqueue2.so") + # self.path("libgstreal.so") + # self.path("libgstrtp.so") + # self.path("libgstrtpmanager.so") + # self.path("libgstrtsp.so") + # self.path("libgstsdpelem.so") + # self.path("libgstselector.so") + # self.path("libgststereo.so") + # self.path("libgsttcp.so") + # self.path("libgsttheora.so") + # self.path("libgsttypefindfunctions.so") + # self.path("libgstudp.so") + # self.path("libgstvideobalance.so") + # self.path("libgstvideobox.so") + # self.path("libgstvideocrop.so") + # self.path("libgstvideoflip.so") + # self.path("libgstvideomixer.so") + # self.path("libgstvideorate.so") + # self.path("libgstvideoscale.so") + # self.path("libgstvideosignal.so") + # self.path("libgstvolume.so") + # self.path("libgstvorbis.so") + # self.path("libgstwavparse.so") - self.end_prefix("../../libraries/universal-darwin/lib_release/gstreamer-plugins") + # self.end_prefix("../../libraries/universal-darwin/lib_release/gstreamer-plugins") # SLVoice and vivox lols @@ -723,13 +739,51 @@ def construct(self): self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") #self.path("vivox-runtime/universal-darwin/SLVoiceAgent.app", "SLVoiceAgent.app") - #libfmodwrapper.dylib - #self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib") - - # our apps -# self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") - self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") + libdir = "../../libraries/universal-darwin/lib_release" + + self.path(os.path.join(os.pardir, + "llcommon", + self.args['configuration'], + "libllcommon.dylib"), + dst="libllcommon.dylib") + + + for libfile in ("libapr-1.0.3.7.dylib", + "libaprutil-1.0.3.8.dylib", + "libexpat.0.5.0.dylib"): + self.path(os.path.join(libdir, libfile), libfile) + # our apps + # self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") + # self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") + + # plugin launcher + self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin.app", "SLPlugin.app") + + # symlinks for SLPlugin.app dependencies + slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources") + for libfile in ("libllcommon.dylib", + "libapr-1.0.3.7.dylib", + "libaprutil-1.0.3.8.dylib", + "libexpat.0.5.0.dylib", + ): + target_lib = os.path.join('../../..', libfile) + self.run_command("ln -sf %(target)r %(link)r" % + {'target': target_lib, + 'link' : os.path.join(slplugin_res_path, libfile)} + ) + + # plugins + if self.prefix(src="", dst="llplugin"): + self.path("../media_plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib") + self.path("../media_plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib") + self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib") + + self.end_prefix("llplugin") + + # Per platform MIME config on the cheap. See SNOW-307 / DEV-41388 + self.path("skins/default/xui/en-us/mime_types_mac.xml", "skins/default/xui/en-us/mime_types.xml") + # command line arguments for connecting to the proper grid self.put_in_file(self.flags_list(), 'arguments.txt') @@ -772,7 +826,7 @@ def package_finish(self): # make sure we don't have stale files laying about self.remove(sparsename, finalname) - self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 300 -layout SPUD' % { + self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 400 -layout SPUD' % { 'sparse':sparsename, 'vol':volname}) @@ -845,7 +899,6 @@ def construct(self): self.path("wrapper.sh","imprudence") self.path("handle_secondlifeprotocol.sh") self.path("register_secondlifeprotocol.sh") - self.path("getvoice.sh") self.end_prefix("linux_tools") self.gather_documents() @@ -857,6 +910,23 @@ def construct(self): # Create an appropriate gridargs.dat for this package, denoting required grid. self.put_in_file(self.flags_list(), 'gridargs.dat') + self.path("linux_tools/launch_url.sh","launch_url.sh") + self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin") + if self.prefix("res-sdl"): + self.path("*") + # recurse + self.end_prefix("res-sdl") + + # plugins + if self.prefix(src="", dst="bin/llplugin"): + self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") + self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so") + self.end_prefix("bin/llplugin") + + # Per platform MIME config on the cheap. See SNOW-307 / DEV-41388 + self.path("skins/default/xui/en-us/mime_types_linux.xml", "skins/default/xui/en-us/mime_types.xml") + + self.path("featuretable_linux.txt") def package_finish(self): @@ -909,18 +979,12 @@ def package_finish(self): class Linux_i686Manifest(LinuxManifest): def construct(self): super(Linux_i686Manifest, self).construct() - self.path("imprudence-stripped","bin/do-not-directly-run-imprudence-bin") -# self.path("../linux_crash_logger/linux-crash-logger-stripped","linux-crash-logger.bin") - self.path("linux_tools/launch_url.sh","launch_url.sh") - if self.prefix("res-sdl"): - self.path("*") - # recurse - self.end_prefix("res-sdl") - - self.path("featuretable_linux.txt") - #self.path("secondlife-i686.supp") + if self.debug(): + self.path("imprudence-bin","bin/do-not-directly-run-imprudence-bin") + else: + self.path("imprudence-stripped","bin/do-not-directly-run-imprudence-bin") - self.path("app_settings/mozilla-runtime-linux-i686") + self.path("../llcommon/libllcommon.so", "lib/libllcommon.so") if (not self.standalone()) and self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"): self.path("libapr-1.so.0") @@ -956,68 +1020,69 @@ def construct(self): # self.path("libpangoxft-1.0.so.0") ##self.path("libpixman-1.so.0") - # Gstreamer libs - self.path("libgstbase-0.10.so.0") - self.path("libgstreamer-0.10.so.0") - self.path("libgstaudio-0.10.so.0") - self.path("libgstbase-0.10.so.0") - self.path("libgstcontroller-0.10.so.0") - self.path("libgstdataprotocol-0.10.so.0") - self.path("libgstinterfaces-0.10.so.0") - self.path("libgstnetbuffer-0.10.so.0") - self.path("libgstpbutils-0.10.so.0") - self.path("libgstriff-0.10.so.0") - self.path("libgstrtp-0.10.so.0") - self.path("libgstrtsp-0.10.so.0") - self.path("libgstsdp-0.10.so.0") - self.path("libgsttag-0.10.so.0") - self.path("libgstvideo-0.10.so.0") - - # Gstreamer plugin dependencies - self.path("libfaad.so.0") - self.path("libogg.so.0") - self.path("libtheora.so.0") - self.path("libvorbis.so.0") - self.path("libvorbisenc.so.2") - self.path("liboil-0.3.so.0") - - # Gstreamer plugins - if self.prefix("gstreamer-plugins"): - self.path("libgstalsa.so") - self.path("libgstasf.so") - self.path("libgstaudioconvert.so") - self.path("libgstaudioresample.so") - self.path("libgstautodetect.so") - self.path("libgstavi.so") - self.path("libgstcoreelements.so") - self.path("libgstcoreindexers.so") - self.path("libgstdecodebin2.so") - self.path("libgstdecodebin.so") - self.path("libgstesd.so") - self.path("libgstfaad.so") - self.path("libgstffmpeg.so") - self.path("libgstgnomevfs.so") - self.path("libgsticydemux.so") - self.path("libgstid3demux.so") - self.path("libgstmpegdemux.so") - self.path("libgstmultifile.so") - self.path("libgstmultipart.so") - self.path("libgstogg.so") - self.path("libgstossaudio.so") - self.path("libgstplaybin.so") - self.path("libgstpulse.so") - self.path("libgstqtdemux.so") - self.path("libgstqueue2.so") - self.path("libgsttcp.so") - self.path("libgsttheora.so") - self.path("libgsttypefindfunctions.so") - self.path("libgstudp.so") - self.path("libgstvideoscale.so") - self.path("libgstvolume.so") - self.path("libgstvorbis.so") - self.path("libgstwavparse.so") +#KILL IT WITH FIRE + ## Gstreamer libs + #self.path("libgstbase-0.10.so.0") + #self.path("libgstreamer-0.10.so.0") + #self.path("libgstaudio-0.10.so.0") + #self.path("libgstbase-0.10.so.0") + #self.path("libgstcontroller-0.10.so.0") + #self.path("libgstdataprotocol-0.10.so.0") + #self.path("libgstinterfaces-0.10.so.0") + #self.path("libgstnetbuffer-0.10.so.0") + #self.path("libgstpbutils-0.10.so.0") + #self.path("libgstriff-0.10.so.0") + #self.path("libgstrtp-0.10.so.0") + #self.path("libgstrtsp-0.10.so.0") + #self.path("libgstsdp-0.10.so.0") + #self.path("libgsttag-0.10.so.0") + #self.path("libgstvideo-0.10.so.0") + + ## Gstreamer plugin dependencies + #self.path("libfaad.so.0") + #self.path("libogg.so.0") + #self.path("libtheora.so.0") + #self.path("libvorbis.so.0") + #self.path("libvorbisenc.so.2") + #self.path("liboil-0.3.so.0") + + ## Gstreamer plugins + #if self.prefix("gstreamer-plugins"): + #self.path("libgstalsa.so") + #self.path("libgstasf.so") + #self.path("libgstaudioconvert.so") + #self.path("libgstaudioresample.so") + #self.path("libgstautodetect.so") + #self.path("libgstavi.so") + #self.path("libgstcoreelements.so") + #self.path("libgstcoreindexers.so") + #self.path("libgstdecodebin2.so") + #self.path("libgstdecodebin.so") + #self.path("libgstesd.so") + #self.path("libgstfaad.so") + #self.path("libgstffmpeg.so") + #self.path("libgstgnomevfs.so") + #self.path("libgsticydemux.so") + #self.path("libgstid3demux.so") + #self.path("libgstmpegdemux.so") + #self.path("libgstmultifile.so") + #self.path("libgstmultipart.so") + #self.path("libgstogg.so") + #self.path("libgstossaudio.so") + #self.path("libgstplaybin.so") + #self.path("libgstpulse.so") + #self.path("libgstqtdemux.so") + #self.path("libgstqueue2.so") + #self.path("libgsttcp.so") + #self.path("libgsttheora.so") + #self.path("libgsttypefindfunctions.so") + #self.path("libgstudp.so") + #self.path("libgstvideoscale.so") + #self.path("libgstvolume.so") + #self.path("libgstvorbis.so") + #self.path("libgstwavparse.so") - self.end_prefix("gstreamer-plugins") + #self.end_prefix("gstreamer-plugins") self.end_prefix("lib") @@ -1035,9 +1100,14 @@ def construct(self): class Linux_x86_64Manifest(LinuxManifest): def construct(self): super(Linux_x86_64Manifest, self).construct() - self.path("imprudence-stripped","bin/do-not-directly-run-imprudence-bin") + if self.debug(): + self.path("imprudence-bin","bin/do-not-directly-run-imprudence-bin") + else: + self.path("imprudence-stripped","bin/do-not-directly-run-imprudence-bin") # self.path("../linux_crash_logger/linux-crash-logger-stripped","linux-crash-logger.bin") + self.path("../llcommon/libllcommon.so", "lib64/libllcommon.so") + self.path("linux_tools/launch_url.sh","launch_url.sh") if self.prefix("res-sdl"): self.path("*") @@ -1047,9 +1117,6 @@ def construct(self): self.path("featuretable_linux.txt") #self.path("secondlife-x86_64.supp") - if not self.standalone(): - self.path("app_settings/mozilla-runtime-linux-x86_64") - if (not self.standalone()) and self.prefix("../../libraries/x86_64-linux/lib_release_client", dst="lib64"): self.path("libapr-1.so.0") self.path("libaprutil-1.so.0") @@ -1077,7 +1144,8 @@ def construct(self): ##self.path("libcairo.so.2") ##self.path("libfontconfig.so.1") ##self.path("libfreetype.so.6") -# self.path("libgdk_pixbuf-2.0.so.0") # use systems gdk pixbufs instead + self.path("libgdk_pixbuf-2.0.so.0") # was commented to use systems gdk pixbufs instead - + # but seems webkit needs it o_O . Packaging for testing now. ##self.path("libgdk-x11-2.0.so.0") ##self.path("libgtk-x11-2.0.so.0") # self.path("libpango-1.0.so.0") # use systems pango instead @@ -1086,69 +1154,70 @@ def construct(self): # self.path("libpangoxft-1.0.so.0") # So we depend system gdk pixbufs and pango anyway. ##self.path("libpixman-1.so.0") - # Gstreamer libs - self.path("libgstbase-0.10.so.0") - self.path("libgstreamer-0.10.so.0") - self.path("libgstaudio-0.10.so.0") - self.path("libgstbase-0.10.so.0") - self.path("libgstcontroller-0.10.so.0") - self.path("libgstdataprotocol-0.10.so.0") - self.path("libgstinterfaces-0.10.so.0") - self.path("libgstnetbuffer-0.10.so.0") - self.path("libgstpbutils-0.10.so.0") - self.path("libgstriff-0.10.so.0") - self.path("libgstrtp-0.10.so.0") - self.path("libgstrtsp-0.10.so.0") - self.path("libgstsdp-0.10.so.0") - self.path("libgsttag-0.10.so.0") - self.path("libgstvideo-0.10.so.0") - - # Gstreamer plugin dependencies - self.path("libfaad.so.0") - self.path("libogg.so.0") - self.path("libtheora.so.0") - self.path("libvorbis.so.0") - self.path("libvorbisenc.so.2") - self.path("liboil-0.3.so.0") - - # Gstreamer plugins - if self.prefix("gstreamer-plugins"): - self.path("libgstalsa.so") - self.path("libgstasf.so") - self.path("libgstaudioconvert.so") - self.path("libgstaudioresample.so") - self.path("libgstautodetect.so") - self.path("libgstavi.so") - self.path("libgstcoreelements.so") - self.path("libgstcoreindexers.so") - self.path("libgstdecodebin2.so") - self.path("libgstdecodebin.so") - self.path("libgstesd.so") - self.path("libgstfaad.so") - self.path("libgstffmpeg.so") - self.path("libgstffmpegcolorspace.so") - self.path("libgstgnomevfs.so") - self.path("libgsticydemux.so") - self.path("libgstid3demux.so") - self.path("libgstmpegdemux.so") - self.path("libgstmultifile.so") - self.path("libgstmultipart.so") - self.path("libgstogg.so") - self.path("libgstossaudio.so") - self.path("libgstplaybin.so") - self.path("libgstpulse.so") - self.path("libgstqtdemux.so") - self.path("libgstqueue2.so") - self.path("libgsttcp.so") - self.path("libgsttheora.so") - self.path("libgsttypefindfunctions.so") - self.path("libgstudp.so") - self.path("libgstvideoscale.so") - self.path("libgstvolume.so") - self.path("libgstvorbis.so") - self.path("libgstwavparse.so") +#KILL IT WITH FIRE + ## Gstreamer libs + #self.path("libgstbase-0.10.so.0") + #self.path("libgstreamer-0.10.so.0") + #self.path("libgstaudio-0.10.so.0") + #self.path("libgstbase-0.10.so.0") + #self.path("libgstcontroller-0.10.so.0") + #self.path("libgstdataprotocol-0.10.so.0") + #self.path("libgstinterfaces-0.10.so.0") + #self.path("libgstnetbuffer-0.10.so.0") + #self.path("libgstpbutils-0.10.so.0") + #self.path("libgstriff-0.10.so.0") + #self.path("libgstrtp-0.10.so.0") + #self.path("libgstrtsp-0.10.so.0") + #self.path("libgstsdp-0.10.so.0") + #self.path("libgsttag-0.10.so.0") + #self.path("libgstvideo-0.10.so.0") + + ## Gstreamer plugin dependencies + #self.path("libfaad.so.0") + #self.path("libogg.so.0") + #self.path("libtheora.so.0") + #self.path("libvorbis.so.0") + #self.path("libvorbisenc.so.2") + #self.path("liboil-0.3.so.0") + + ## Gstreamer plugins + #if self.prefix("gstreamer-plugins"): + #self.path("libgstalsa.so") + #self.path("libgstasf.so") + #self.path("libgstaudioconvert.so") + #self.path("libgstaudioresample.so") + #self.path("libgstautodetect.so") + #self.path("libgstavi.so") + #self.path("libgstcoreelements.so") + #self.path("libgstcoreindexers.so") + #self.path("libgstdecodebin2.so") + #self.path("libgstdecodebin.so") + #self.path("libgstesd.so") + #self.path("libgstfaad.so") + #self.path("libgstffmpeg.so") + #self.path("libgstffmpegcolorspace.so") + #self.path("libgstgnomevfs.so") + #self.path("libgsticydemux.so") + #self.path("libgstid3demux.so") + #self.path("libgstmpegdemux.so") + #self.path("libgstmultifile.so") + #self.path("libgstmultipart.so") + #self.path("libgstogg.so") + #self.path("libgstossaudio.so") + #self.path("libgstplaybin.so") + #self.path("libgstpulse.so") + #self.path("libgstqtdemux.so") + #self.path("libgstqueue2.so") + #self.path("libgsttcp.so") + #self.path("libgsttheora.so") + #self.path("libgsttypefindfunctions.so") + #self.path("libgstudp.so") + #self.path("libgstvideoscale.so") + #self.path("libgstvolume.so") + #self.path("libgstvorbis.so") + #self.path("libgstwavparse.so") - self.end_prefix("gstreamer-plugins") + #self.end_prefix("gstreamer-plugins") self.end_prefix("lib64") diff --git a/linden/indra/newview/viewertime.cpp b/linden/indra/newview/viewertime.cpp index 06dd91a24..06436b648 100644 --- a/linden/indra/newview/viewertime.cpp +++ b/linden/indra/newview/viewertime.cpp @@ -47,6 +47,9 @@ ViewerTime* gViewerTime = 0; // We use statics here for speed reasons bool ViewerTime::sUse24HourTime = false; bool ViewerTime::sUseUTCTime = false; +bool ViewerTime::sUseTimeOffset = false; +S32 ViewerTime::sTimeOffset = 0; +bool ViewerTime::sTimeOffsetDST = false; std::vector<std::string> ViewerTime::sDays; std::vector<std::string> ViewerTime::sMonths; @@ -87,16 +90,21 @@ void ViewerTime::refresh() // There's only one internal tm buffer. struct tm* internal_time; - if (!sUseUTCTime) + if (sUseUTCTime) { - // Convert to Pacific, based on server's opinion of whether - // it's daylight savings time there. - internal_time = utc_to_pacific_time(utc_time, gPacificDaylightTime); + time(&utc_time); + internal_time = gmtime(&utc_time); + } + else if (sUseTimeOffset) + { + //Its a UTC offset, deal with it + internal_time = utc_to_offset_time(utc_time, sTimeOffset, sTimeOffsetDST); } else { - time(&utc_time); - internal_time = gmtime(&utc_time); + // Convert to Pacific, based on server's opinion of whether + // it's daylight savings time there. + internal_time = utc_to_pacific_time(utc_time, gPacificDaylightTime); } mMinute = internal_time->tm_min; diff --git a/linden/indra/newview/viewertime.h b/linden/indra/newview/viewertime.h index 525a2bcb4..f7a80a6f6 100644 --- a/linden/indra/newview/viewertime.h +++ b/linden/indra/newview/viewertime.h @@ -59,6 +59,9 @@ class ViewerTime static bool sUse24HourTime; static bool sUseUTCTime; + static bool sUseTimeOffset; + static S32 sTimeOffset; + static bool sTimeOffsetDST; void updateTimeFormat(const U32& index); diff --git a/linden/indra/newview/viewerversion.cpp b/linden/indra/newview/viewerversion.cpp index 95c8f7690..cb541484c 100644 --- a/linden/indra/newview/viewerversion.cpp +++ b/linden/indra/newview/viewerversion.cpp @@ -40,7 +40,7 @@ S32 ViewerVersion::sVersionMinor = 0; S32 ViewerVersion::sVersionPatch = 0; std::string ViewerVersion::sVersionTest = ""; -const std::string ViewerVersion::sViewerName = "Imprudence"; +const std::string ViewerVersion::sViewerName = "MoonWorld"; ViewerVersion::ViewerVersion() { diff --git a/linden/indra/newview/viewerversion.h b/linden/indra/newview/viewerversion.h index d67cee5f2..bd4baec72 100644 --- a/linden/indra/newview/viewerversion.h +++ b/linden/indra/newview/viewerversion.h @@ -49,7 +49,7 @@ class ViewerVersion static S32 getImpPatchVersion() { return sVersionPatch; } // Returns the test version of Imprudence static std::string getImpTestVersion() { return sVersionTest; } - // Returns the name of the viewer. Currently always "Imprudence" + // Returns the name of the viewer. Currently always "MoonWorld" static std::string getImpViewerName() { return sViewerName; } // Returns the major version of Second Life diff --git a/linden/indra/newview/windlightsettingsupdate.cpp b/linden/indra/newview/windlightsettingsupdate.cpp new file mode 100644 index 000000000..ad6e7c968 --- /dev/null +++ b/linden/indra/newview/windlightsettingsupdate.cpp @@ -0,0 +1,200 @@ +/* + * @file kowopenregionsettings.cpp + * @brief Handler for OpenRegionInfo event queue message. + * + * Copyright (c) 2010, Patrick Sapinski + * + * The source code in this file ("Source Code") is provided to you + * under the terms of the GNU General Public License, version 2.0 + * ("GPL"). Terms of the GPL can be found in doc/GPL-license.txt in + * this distribution, or online at + * http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL SOURCE CODE IS PROVIDED "AS IS." THE AUTHOR MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + */ + +#include "llviewerprecompiledheaders.h" +#include "llhttpnode.h" +#include "hippolimits.h" +#include "llfloatertools.h" +#include "llviewercontrol.h" +#include "llagent.h" +#include "llsurface.h" +#include "llviewerregion.h" +#include "llviewerobject.h" + +#include "linden_common.h" +#include "llwaterparammanager.h" +#include "llwaterparamset.h" +#include "llwlparammanager.h" +#include "llwlparamset.h" +#include "message.h" +#include "meta7windlight.h" +#include "lightshare.h" +#include "wlsettingsmanager.h" + +//DEBUG includes +//#include "llsdserialize.h" //LLSDNotationStreamer - for dumping LLSD to string + +class WindLightSettingsUpdate : public LLHTTPNode +{ + /*virtual*/ void post( + LLHTTPNode::ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + if (!input.isMap() || !input.has("body")) + { + llinfos << "malformed WindLightSettingsUpdate update!" << llendl; + return; + } + LLWaterParamSet* mWater; + LLWLParamSet* mSky; + LLUUID* mWaterNormal; + + mWater = new LLWaterParamSet(); + mSky = new LLWLParamSet(); + mWaterNormal = new LLUUID(); + + LLSD body = input["body"]; + + mWater->set("waterFogColor", + body["waterColorX"].asReal() / 256.f, + body["waterColorY"].asReal() / 256.f, + body["waterColorZ"].asReal() / 256.f, + body["waterColorW"].asReal() / 256.f); + mWater->set("waterFogDensity", body["waterFogDensityExponent"].asReal()); + mWater->set("underWaterFogMod", body["underwaterFogModifier"].asReal()); + mWater->set("normScale", body["reflectionWaveletScaleX"].asReal(), + body["reflectionWaveletScaleY"].asReal(), + body["reflectionWaveletScaleZ"].asReal()); + mWater->set("fresnelScale", body["fresnelScale"].asReal()); + mWater->set("fresnelOffset", body["fresnelOffset"].asReal()); + mWater->set("scaleAbove", body["refractScaleAbove"].asReal()); + mWater->set("scaleBelow", body["refractScaleBelow"].asReal()); + mWater->set("blurMultiplier", body["blurMultiplier"].asReal()); + mWater->set("wave2Dir", body["bigWaveDirectionX"].asReal(), + body["bigWaveDirectionY"].asReal()); + mWater->set("wave1Dir", body["littleWaveDirectionX"].asReal(), + body["littleWaveDirectionY"].asReal()); + mWaterNormal->parseUUID(body["normalMapTexture"].asUUID().asString(), mWaterNormal); + + mSky->setSunAngle(body["sunMoonPosition"].asReal()); + mSky->setEastAngle(body["eastAngle"].asReal()); + + mSky->set("sunlight_color", + body["sunMoonColorX"].asReal() * 3.0f, + body["sunMoonColorY"].asReal() * 3.0f, + body["sunMoonColorZ"].asReal() * 3.0f, + body["sunMoonColorW"].asReal() * 3.0f); + + mSky->set("ambient", + body["ambientX"].asReal() * 3.0f, + body["ambientY"].asReal() * 3.0f, + body["ambientZ"].asReal() * 3.0f, + body["ambientW"].asReal() * 3.0f); + + mSky->set("blue_horizon", + body["horizonX"].asReal() * 2.0f, + body["horizonY"].asReal() * 2.0f, + body["horizonZ"].asReal() * 2.0f, + body["horizonW"].asReal() * 2.0f); + + mSky->set("blue_density", + body["blueDensityX"].asReal(), + body["blueDensityY"].asReal(), + body["blueDensityZ"].asReal(), + 1.0); + + mSky->set("haze_horizon", + body["hazeHorizon"].asReal(), + body["hazeHorizon"].asReal(), + body["hazeHorizon"].asReal(), + 1.f); + + mSky->set("haze_density", + body["hazeDensity"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("cloud_shadow", + body["cloudCoverage"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("density_multiplier", + body["densityMultiplier"].asReal() / 1000.0f, + 0.f, 0.f, 1.f); + + mSky->set("distance_multiplier", + body["distanceMultiplier"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("max_y", + body["maxAltitude"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("cloud_color", + body["cloudColorX"].asReal(), + body["cloudColorY"].asReal(), + body["cloudColorZ"].asReal(), + body["cloudColorW"].asReal()); + + mSky->set("cloud_pos_density1", + body["cloudXYDensityX"].asReal(), + body["cloudXYDensityY"].asReal(), + body["cloudXYDensityZ"].asReal(), + 1.f); + + mSky->set("cloud_pos_density2", + body["cloudDetailXYDensityX"].asReal(), + body["cloudDetailXYDensityY"].asReal(), + body["cloudDetailXYDensityZ"].asReal(), + 1.f); + + mSky->set("cloud_scale", + body["cloudScale"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("gamma", + body["sceneGamma"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("glow", + (2 - body["sunGlowSize"].asReal()) * 20, + 0.f, + -body["sunGlowFocus"].asReal() * 5, + 1.f); + + mSky->setCloudScrollX(body["cloudScrollX"].asReal() + 10.0f); + mSky->setCloudScrollY(body["cloudScrollY"].asReal() + 10.0f); + + mSky->setEnableCloudScrollX(!body["cloudScrollXLock"].asBoolean()); + mSky->setEnableCloudScrollY(!body["cloudScrollYLock"].asBoolean()); + + mSky->setStarBrightness(body["starBrightness"].asReal()); + + mSky->set("fade", body["fade"].asReal()); + + //Update this here.. since it isn't a part of WL... go figure + gHippoLimits->skyUseClassicClouds = body["drawClassicClouds"].asBoolean(); + gSavedSettings.setF32("ClassicCloudHeight",body["classicCloudHeight"].asReal()); + gSavedSettings.setF32("ClassicCloudRange",body["classicCloudRange"].asReal()); + + WLSettingsManager::Apply(mSky, mWater, mWaterNormal); +} +}; + +LLHTTPRegistration<WindLightSettingsUpdate> +gHTTPRegistrationWindLightSettingsUpdate( + "/message/WindLightSettingsUpdate"); \ No newline at end of file diff --git a/linden/indra/newview/wlfloatermanager.cpp b/linden/indra/newview/wlfloatermanager.cpp new file mode 100644 index 000000000..63abe14ac --- /dev/null +++ b/linden/indra/newview/wlfloatermanager.cpp @@ -0,0 +1,281 @@ +/** +* @file wlfloaterwindlightsend.cpp +* @brief WLFloaterWindLightSend class definition +* +* $LicenseInfo:firstyear=2007&license=viewergpl$ +* +* Copyright (c) 2007-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterwindlight.h" + +#include "pipeline.h" +#include "llsky.h" + +#include "llsliderctrl.h" +#include "llmultislider.h" +#include "llmultisliderctrl.h" +#include "llspinctrl.h" +#include "llcheckboxctrl.h" +#include "lluictrlfactory.h" +#include "llviewercamera.h" +#include "llcombobox.h" +#include "lllineeditor.h" +#include "llfloaterdaycycle.h" +#include "lltabcontainer.h" +#include "llboost.h" + +#include "llagent.h" +#include "llinventorymodel.h" +#include "llviewerinventory.h" + +#include "v4math.h" +#include "llviewerdisplay.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "llsavedsettingsglue.h" + +#include "llwlparamset.h" +#include "llwlparammanager.h" +#include "llwaterparammanager.h" +#include "llpostprocess.h" +#include "hippolimits.h" +#include "wlfloatermanager.h" +#include "llviewerregion.h" +#include "llviewerparcelmgr.h" +#include "llparcel.h" +#include "wlretrievesettings.h" +#include "wlsettingsmanager.h" +#include "wlfloaterwindlightsend.h" + +#undef max +WLFloaterManager* WLFloaterManager::sWindLight; +std::map<std::string, LLWLParamSet*> WLFloaterManager::mWLParamList; +std::map<std::string, LLWaterParamSet*> WLFloaterManager::mWaterParamList; +std::map<std::string, LLUUID*> WLFloaterManager::mWaterNormalParamList; +std::map<std::string, LLSD> WLFloaterManager::mMinAltParamList; +std::map<std::string, LLSD> WLFloaterManager::mMaxAltParamList; +std::map<std::string, LLSD> WLFloaterManager::mFadeParamList; + +WLFloaterManager::WLFloaterManager() : LLFloater(std::string("windlight manager floater")) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_windlight_manager.xml"); + + // load it up + initCallbacks(); +} + +WLFloaterManager::~WLFloaterManager() +{ +} + +void WLFloaterManager::initCallbacks(void) { + + // help buttons + childSetAction("this_parcel", onGetThisParcel, this); + childSetAction("all_parcels", onGetAllParcels, this); + childSetAction("this_region", onGetThisRegion, this); + childSetAction("show", onShow, this); + childSetAction("set_to_current", onSetToCurrent, this); + childSetAction("remove", onRemove, this); +} + +void WLFloaterManager::onClickHelp(void* data) +{ + LLFloaterWindLight* self = LLFloaterWindLight::instance(); + + const std::string xml_alert = *(std::string*)data; + LLNotifications::instance().add(self->contextualNotification(xml_alert)); +} + +void WLFloaterManager::initHelpBtn(const std::string& name, const std::string& xml_alert) +{ + childSetAction(name, onClickHelp, new std::string(xml_alert)); +} + +// static +WLFloaterManager* WLFloaterManager::instance() +{ + if (!sWindLight) + { + sWindLight = new WLFloaterManager(); + sWindLight->open(); + sWindLight->setFocus(TRUE); + } + return sWindLight; +} + +void WLFloaterManager::show() +{ + if (!sWindLight) + { + WLFloaterManager::instance(); + } + else + { + if (sWindLight->getVisible()) + { + sWindLight->close(); + } + else + { + sWindLight->open(); + } + } +} + +bool WLFloaterManager::isOpen() +{ + if (sWindLight != NULL) { + return true; + } + return false; +} + +// virtual +void WLFloaterManager::onClose(bool app_quitting) +{ + if (sWindLight) + { + sWindLight->setVisible(FALSE); + } +} + +void WLFloaterManager::onGetThisRegion(void* userData) +{ + LLSD body; + + //Send the update CAPS to the server + std::string url = gAgent.getRegion()->getCapability("RetrieveWindLightSettings"); + if (!url.empty()) + { + body["RegionID"] = gAgent.getRegion()->getRegionID(); + LLHTTPClient::post(url, body, new retrieveWindlightSettings(body)); + } +} + +void WLFloaterManager::onGetThisParcel(void* userData) +{ + LLSD body; + + //Send the update CAPS to the server + std::string url = gAgent.getRegion()->getCapability("RetrieveWindLightSettings"); + if (!url.empty()) + { + body["ParcelID"] = LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID(); + LLHTTPClient::post(url, body, new retrieveWindlightSettings(body)); + } +} +void WLFloaterManager::onGetAllParcels(void* userData) +{ + LLSD body; + + //Send the update CAPS to the server + std::string url = gAgent.getRegion()->getCapability("RetrieveWindLightSettings"); + if (!url.empty()) + { + body["ParcelID"] = -1; + LLHTTPClient::post(url, body, new retrieveWindlightSettings(body)); + } +} + +void WLFloaterManager::onShow(void* userData) +{ + WLFloaterManager* mgr = WLFloaterManager::instance(); + LLComboBox* comboBox = mgr->getChild<LLComboBox>("WLSettingsCombo"); + std::string name = comboBox->getSelectedItemLabel(); + //Set the new settings up + LLWLParamSet* mSky = mgr->mWLParamList[name]; + LLWaterParamSet* mWater = mgr->mWaterParamList[name]; + LLUUID* mWaterNormal = mgr->mWaterNormalParamList[name]; + if(mSky != NULL && mWater != NULL && mWaterNormal != NULL) + WLSettingsManager::Apply(mSky, mWater, mWaterNormal); +} +void WLFloaterManager::onSetToCurrent(void* userData) +{ + WLFloaterManager* mgr = WLFloaterManager::instance(); + LLComboBox* comboBox = mgr->getChild<LLComboBox>("WLSettingsCombo"); + std::string name = comboBox->getSelectedItemLabel(); + + LLWLParamSet* mSky = mgr->mWLParamList[name]; + LLWaterParamSet* mWater = mgr->mWaterParamList[name]; + LLUUID* mWaterNormal = mgr->mWaterNormalParamList[name]; + LLSD fade = mgr->mFadeParamList[name]; + LLSD minAlt = mgr->mMinAltParamList[name]; + LLSD maxAlt = mgr->mMaxAltParamList[name]; + + int type = 1; + if(name == "(Region Settings)") + { + type = 0; + } + + if(mSky != NULL && mWater != NULL && mWaterNormal != NULL) + WLFloaterWindLightSend::SendSettings(false, type, NULL, *mSky, *mWater, fade, minAlt, maxAlt, *mWaterNormal); +} +void WLFloaterManager::onRemove(void* userData) +{ + WLFloaterManager* mgr = WLFloaterManager::instance(); + LLComboBox* comboBox = mgr->getChild<LLComboBox>("WLSettingsCombo"); + std::string name = comboBox->getSelectedItemLabel(); + + LLWLParamSet* mSky = mgr->mWLParamList[name]; + LLWaterParamSet* mWater = mgr->mWaterParamList[name]; + LLUUID* mWaterNormal = mgr->mWaterNormalParamList[name]; + LLSD fade = mgr->mFadeParamList[name]; + LLSD minAlt = mgr->mMinAltParamList[name]; + LLSD maxAlt = mgr->mMaxAltParamList[name]; + + int type = 1; + if(name == "(Region Settings)") + { + type = 0; + } + + if(mSky != NULL && mWater != NULL && mWaterNormal != NULL) + WLFloaterWindLightSend::SendSettings(true, type, false, *mSky, *mWater, fade, minAlt, maxAlt, *mWaterNormal); +} + + +//static +void WLFloaterManager::UpdateFloater() +{ + WLFloaterManager* mgr = WLFloaterManager::instance(); + LLComboBox* comboBox = mgr->getChild<LLComboBox>("WLSettingsCombo"); + comboBox->clear(); + comboBox->removeall(); + std::map<std::string, LLWLParamSet*>::iterator mIt = + WLFloaterManager::instance()->mWLParamList.begin(); + for(; mIt != WLFloaterManager::instance()->mWLParamList.end(); mIt++) + { + comboBox->add(mIt->first); + } + //Reorder them + comboBox->sortByName(); +} + diff --git a/linden/indra/newview/wlfloatermanager.h b/linden/indra/newview/wlfloatermanager.h new file mode 100644 index 000000000..0a2d0ca88 --- /dev/null +++ b/linden/indra/newview/wlfloatermanager.h @@ -0,0 +1,93 @@ +/** + * @file wlfloaterwindlightsend.h + * @brief WLFloaterWindLightSend class definition + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +/* + * Menu for adjusting the atmospheric settings of the world + */ + +#include "llfloater.h" + +#include <vector> +#include "llwlparamset.h" + +struct WLColorControl; +struct WLFloatControl; + + +/// Menuing system for all of windlight's functionality +class WLFloaterManager : public LLFloater +{ +public: + + WLFloaterManager(); + virtual ~WLFloaterManager(); + + /// initialize all + void initCallbacks(void); + + /// one and one instance only + static WLFloaterManager* instance(); + + // help button stuff + static void onClickHelp(void* data); + void initHelpBtn(const std::string& name, const std::string& xml_alert); + + static void onGetThisRegion(void* userData); + static void onGetThisParcel(void* userData); + static void onGetAllParcels(void* userData); + static void onShow(void* userData); + static void onSetToCurrent(void* userData); + static void onRemove(void* userData); + + //// menu management + + /// show off our menu + static void show(); + + /// return if the menu exists or not + static bool isOpen(); + + /// stuff to do on exit + virtual void onClose(bool app_quitting); + + static void UpdateFloater(); + static std::map<std::string, LLWLParamSet*> mWLParamList; + static std::map<std::string, LLWaterParamSet*> mWaterParamList; + static std::map<std::string, LLUUID*> mWaterNormalParamList; + static std::map<std::string, LLSD> mMinAltParamList; + static std::map<std::string, LLSD> mMaxAltParamList; + static std::map<std::string, LLSD> mFadeParamList; + +private: + // one instance on the inside + static WLFloaterManager* sWindLight; +}; \ No newline at end of file diff --git a/linden/indra/newview/wlfloaterwindlightsend.cpp b/linden/indra/newview/wlfloaterwindlightsend.cpp new file mode 100644 index 000000000..e6148edd1 --- /dev/null +++ b/linden/indra/newview/wlfloaterwindlightsend.cpp @@ -0,0 +1,300 @@ +/** +* @file wlfloaterwindlightsend.cpp +* @brief WLFloaterWindLightSend class definition +* +* $LicenseInfo:firstyear=2007&license=viewergpl$ +* +* Copyright (c) 2007-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterwindlight.h" + +#include "pipeline.h" +#include "llsky.h" + +#include "llsliderctrl.h" +#include "llmultislider.h" +#include "llmultisliderctrl.h" +#include "llspinctrl.h" +#include "llcheckboxctrl.h" +#include "lluictrlfactory.h" +#include "llviewercamera.h" +#include "llcombobox.h" +#include "lllineeditor.h" +#include "llfloaterdaycycle.h" +#include "lltabcontainer.h" +#include "llboost.h" + +#include "llagent.h" +#include "llinventorymodel.h" +#include "llviewerinventory.h" + +#include "v4math.h" +#include "llviewerdisplay.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "llsavedsettingsglue.h" + +#include "llwlparamset.h" +#include "llwlparammanager.h" +#include "llwaterparammanager.h" +#include "llpostprocess.h" +#include "hippolimits.h" +#include "wlfloaterwindlightsend.h" +#include "llviewerregion.h" + +#undef max + + +WLFloaterWindLightSend* WLFloaterWindLightSend::sWindLight = NULL; + +WLFloaterWindLightSend::WLFloaterWindLightSend() : LLFloater(std::string("windlight send floater")) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_windlight_remote_save.xml"); + + // load it up + initCallbacks(); +} + +WLFloaterWindLightSend::~WLFloaterWindLightSend() +{ +} + +void WLFloaterWindLightSend::initCallbacks(void) { + + // help buttons + initHelpBtn("fade_help", "HelpBlueHorizon"); + initHelpBtn("override_parcel_default_help", "HelpHazeHorizon"); + initHelpBtn("override_parcel_help", "HelpBlueDensity"); + initHelpBtn("max_altitude_help", "HelpHazeDensity"); + initHelpBtn("min_altitude_help", "HelpDensityMult"); + childSetAction("button_region_send_to_server", onSaveRegionPreset, this); + childSetAction("button_parcel_send_to_server", onSaveParcelPreset, this); +} + +void WLFloaterWindLightSend::onClickHelp(void* data) +{ + LLFloaterWindLight* self = LLFloaterWindLight::instance(); + + const std::string xml_alert = *(std::string*)data; + LLNotifications::instance().add(self->contextualNotification(xml_alert)); +} + +void WLFloaterWindLightSend::initHelpBtn(const std::string& name, const std::string& xml_alert) +{ + childSetAction(name, onClickHelp, new std::string(xml_alert)); +} + +// static +WLFloaterWindLightSend* WLFloaterWindLightSend::instance() +{ + if (!sWindLight) + { + sWindLight = new WLFloaterWindLightSend(); + sWindLight->open(); + sWindLight->setFocus(TRUE); + } + return sWindLight; +} + +void WLFloaterWindLightSend::show() +{ + if (!sWindLight) + { + WLFloaterWindLightSend::instance(); + } + else + { + if (sWindLight->getVisible()) + { + sWindLight->close(); + } + else + { + sWindLight->open(); + } + } +} + +bool WLFloaterWindLightSend::isOpen() +{ + if (sWindLight != NULL) { + return true; + } + return false; +} + +// virtual +void WLFloaterWindLightSend::onClose(bool app_quitting) +{ + if (sWindLight) + { + sWindLight->setVisible(FALSE); + } +} + +void WLFloaterWindLightSend::onSaveRegionPreset(void* userData) +{ + int RegionType = 0; + SendSettings(false, RegionType, + WLFloaterWindLightSend::instance()->childGetValue("override_parcel"), + LLWLParamManager::instance()->mCurParams, + LLWaterParamManager::instance()->mCurParams, + WLFloaterWindLightSend::instance()->childGetValue("Fade"), + WLFloaterWindLightSend::instance()->childGetValue("min_altitude"), + WLFloaterWindLightSend::instance()->childGetValue("max_altitude"), + LLWaterParamManager::instance()->getNormalMapID()); +} +void WLFloaterWindLightSend::onSaveParcelPreset(void* userData) +{ + int ParcelType = 1; + SendSettings(false, ParcelType, false, LLWLParamManager::instance()->mCurParams, + LLWaterParamManager::instance()->mCurParams, + WLFloaterWindLightSend::instance()->childGetValue("Fade"), + WLFloaterWindLightSend::instance()->childGetValue("min_altitude"), + WLFloaterWindLightSend::instance()->childGetValue("max_altitude"), + LLWaterParamManager::instance()->getNormalMapID()); +} +void WLFloaterWindLightSend::SendSettings(bool remove, int type, bool overrideParcels, + LLWLParamSet mSky, LLWaterParamSet mWater, + LLSD fade, LLSD minAlt, LLSD maxAlt, + LLUUID normalMap) +{ + LLSD body; + std::string url = gAgent.getRegion()->getCapability("DispatchWindLightSettings"); + if (!url.empty()) + { + bool error; + + body["type"] = type; + body["remove"] = remove; + body["fade"] = fade; + body["maxEffectiveAltitude"] = maxAlt; + body["minEffectiveAltitude"] = minAlt; + if(overrideParcels == true || overrideParcels == false) + body["overrideParcels"] = overrideParcels; + + LLVector4 v = mSky.getVector("ambient", error); + body["ambientX"] = v[0] / 3.0; + body["ambientY"] = v[1] / 3.0; + body["ambientZ"] = v[2] / 3.0; + body["ambientW"] = v[3] / 3.0; + + body["eastAngle"] = mSky.getEastAngle(); + body["sunMoonPosition"] = mSky.getSunAngle(); + + v = mSky.getVector("sunlight_color",error); + body["sunMoonColorX"] = v[0] / 3.0; + body["sunMoonColorY"] = v[1] / 3.0; + body["sunMoonColorZ"] = v[2] / 3.0; + body["sunMoonColorW"] = v[3] / 3.0; + + v = mSky.getVector("blue_horizon",error); + body["horizonX"] = v[0] / 2.0; + body["horizonY"] = v[1] / 2.0; + body["horizonZ"] = v[2] / 2.0; + body["horizonW"] = v[3] / 2.0; + + v = mSky.getVector("blue_density",error); + body["blueDensityX"] = v[0]; + body["blueDensityY"] = v[1]; + body["blueDensityZ"] = v[2]; + + v = mSky.getVector("haze_horizon",error); + body["hazeHorizon"] = v[0]; + + body["hazeDensity"] = mSky.getFloat("haze_density",error); + body["cloudCoverage"] = mSky.getFloat("cloud_shadow",error); + body["densityMultiplier"] = mSky.getFloat("density_multiplier",error) * 1000; + body["distanceMultiplier"] = mSky.getFloat("distance_multiplier",error); + body["maxAltitude"] = mSky.getFloat("max_y",error); + + v = mSky.getVector("cloud_color",error); + body["cloudColorX"] = v[0]; + body["cloudColorY"] = v[1]; + body["cloudColorZ"] = v[2]; + body["cloudColorW"] = v[3]; + + v = mSky.getVector("cloud_pos_density1",error); + body["cloudXYDensityX"] = v[0]; + body["cloudXYDensityY"] = v[1]; + body["cloudXYDensityZ"] = v[2]; + + v = mSky.getVector("cloud_pos_density2",error); + body["cloudDetailXYDensityX"] = v[0]; + body["cloudDetailXYDensityY"] = v[1]; + body["cloudDetailXYDensityZ"] = v[2]; + + v = mSky.getVector("glow",error); + body["sunGlowSize"] = -((v[0]/ 20) - 2); + body["sunGlowFocus"] = -v[2] / 5; + + body["cloudScale"] = mSky.getFloat("cloud_scale",error); + body["sceneGamma"] = mSky.getFloat("gamma",error); + body["cloudScrollX"] = mSky.getCloudScrollX() - 10; + body["cloudScrollY"] = mSky.getCloudScrollY() - 10; + body["cloudScrollXLock"] = !mSky.getEnableCloudScrollX(); + body["cloudScrollYLock"] = !mSky.getEnableCloudScrollY(); + body["starBrightness"] = mSky.getStarBrightness(); + body["drawClassicClouds"] = gHippoLimits->skyUseClassicClouds; + body["classicCloudHeight"] = gSavedSettings.getF32("ClassicCloudHeight"); + body["classicCloudRange"] = gSavedSettings.getF32("ClassicCloudRange"); + + LLVector3 vvv = mWater.getVector3("normScale",error); + body["reflectionWaveletScaleX"] = vvv[0]; + body["reflectionWaveletScaleY"] = vvv[1]; + body["reflectionWaveletScaleZ"] = vvv[2]; + + v = mWater.getVector4("waterFogColor",error); + body["waterColorX"] = v[0] * 256.0; + body["waterColorY"] = v[1] * 256.0; + body["waterColorZ"] = v[2] * 256.0; + body["waterColorW"] = v[3] * 256.0; + + body["waterFogDensityExponent"] = mWater.getFloat("waterFogDensity", error); + body["underwaterFogModifier"] = mWater.getFloat("underWaterFogMod", error); + + body["fresnelScale"] = mWater.getFloat("fresnelScale", error); + body["fresnelOffset"] = mWater.getFloat("fresnelOffset", error); + body["refractScaleAbove"] = mWater.getFloat("scaleAbove", error); + body["refractScaleBelow"] = mWater.getFloat("scaleBelow", error); + body["blurMultiplier"] = mWater.getFloat("blurMultiplier", error); + + LLVector2 vv = mWater.getVector2("wave1Dir",error); + body["littleWaveDirectionX"] = vv[0]; + body["littleWaveDirectionY"] = vv[1]; + + vv = mWater.getVector2("wave2Dir",error); + body["bigWaveDirectionX"] = vv[0]; + body["bigWaveDirectionY"] = vv[1]; + + body["normalMapTexture"] = normalMap; + + LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); + } +} \ No newline at end of file diff --git a/linden/indra/newview/wlfloaterwindlightsend.h b/linden/indra/newview/wlfloaterwindlightsend.h new file mode 100644 index 000000000..acd438606 --- /dev/null +++ b/linden/indra/newview/wlfloaterwindlightsend.h @@ -0,0 +1,88 @@ +/** + * @file wlfloaterwindlightsend.h + * @brief WLFloaterWindLightSend class definition + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +/* + * Menu for adjusting the atmospheric settings of the world + */ + +#include "llfloater.h" + +#include <vector> +#include "llwlparamset.h" +#include "llwaterparamset.h" +#include "llsd.h" + +struct WLColorControl; +struct WLFloatControl; + + +/// Menuing system for all of windlight's functionality +class WLFloaterWindLightSend : public LLFloater +{ +public: + + WLFloaterWindLightSend(); + virtual ~WLFloaterWindLightSend(); + + /// initialize all + void initCallbacks(void); + + /// one and one instance only + static WLFloaterWindLightSend* instance(); + + // help button stuff + static void onClickHelp(void* data); + void initHelpBtn(const std::string& name, const std::string& xml_alert); + + static void onSaveParcelPreset(void* userData); + static void onSaveRegionPreset(void* userData); + + //// menu management + + /// show off our menu + static void show(); + + /// return if the menu exists or not + static bool isOpen(); + + /// stuff to do on exit + virtual void onClose(bool app_quitting); + + static void SendSettings(bool remove, int type, bool overrideParcel, + LLWLParamSet mSky, LLWaterParamSet mWater, + LLSD Fade, LLSD minAlt, LLSD maxAlt, + LLUUID normalMap); + +private: + // one instance on the inside + static WLFloaterWindLightSend* sWindLight; +}; \ No newline at end of file diff --git a/linden/indra/newview/wlretrievesettings.cpp b/linden/indra/newview/wlretrievesettings.cpp new file mode 100644 index 000000000..afa84f25a --- /dev/null +++ b/linden/indra/newview/wlretrievesettings.cpp @@ -0,0 +1,238 @@ +/** +* @file wlfloaterwindlightsend.cpp +* @brief WLFloaterWindLightSend class definition +* +* $LicenseInfo:firstyear=2007&license=viewergpl$ +* +* Copyright (c) 2007-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterwindlight.h" + +#include "pipeline.h" +#include "llsky.h" + +#include "llsliderctrl.h" +#include "llmultislider.h" +#include "llmultisliderctrl.h" +#include "llspinctrl.h" +#include "llcheckboxctrl.h" +#include "lluictrlfactory.h" +#include "llviewercamera.h" +#include "llcombobox.h" +#include "lllineeditor.h" +#include "llfloaterdaycycle.h" +#include "lltabcontainer.h" +#include "llboost.h" + +#include "llagent.h" +#include "llinventorymodel.h" +#include "llviewerinventory.h" + +#include "v4math.h" +#include "llviewerdisplay.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "llsavedsettingsglue.h" + +#include "llwlparamset.h" +#include "llwlparammanager.h" +#include "llwaterparammanager.h" +#include "llpostprocess.h" +#include "hippolimits.h" +#include "wlfloaterwindlightsend.h" +#include "llviewerregion.h" +#include "wlsettingsmanager.h" +#include "lightshare.h" + +#include "linden_common.h" +#include "llviewercontrol.h" +#include "message.h" +#include "meta7windlight.h" +#include "wlretrievesettings.h" +#include "wlfloatermanager.h" + +#undef max + +//If we get back a normal response, handle it here +void retrieveWindlightSettings::result(const LLSD& content) +{ + //Clear the lists first + WLFloaterManager::mMinAltParamList.clear(); + WLFloaterManager::mMaxAltParamList.clear(); + WLFloaterManager::mFadeParamList.clear(); + WLFloaterManager::mWLParamList.clear(); + WLFloaterManager::mWaterParamList.clear(); + WLFloaterManager::mWaterNormalParamList.clear(); + + for(LLSD::array_const_iterator wls = content["WindLight"].beginArray(); + wls != content["WindLight"].endArray(); + ++wls) + { + LLSD windLightLLSD = *wls; + LLWaterParamSet* mWater; + LLWLParamSet* mSky; + LLUUID* mWaterNormal; + + mWater = new LLWaterParamSet(); + mSky = new LLWLParamSet(); + mWaterNormal = new LLUUID(); + + mWater->set("waterFogColor", + windLightLLSD["waterColorX"].asReal() / 256.f, + windLightLLSD["waterColorY"].asReal() / 256.f, + windLightLLSD["waterColorZ"].asReal() / 256.f, + windLightLLSD["waterColorW"].asReal() / 256.f); + mWater->set("waterFogDensity", windLightLLSD["waterFogDensityExponent"].asReal()); + mWater->set("underWaterFogMod", windLightLLSD["underwaterFogModifier"].asReal()); + mWater->set("normScale", windLightLLSD["reflectionWaveletScaleX"].asReal(), + windLightLLSD["reflectionWaveletScaleY"].asReal(), + windLightLLSD["reflectionWaveletScaleZ"].asReal()); + mWater->set("fresnelScale", windLightLLSD["fresnelScale"].asReal()); + mWater->set("fresnelOffset", windLightLLSD["fresnelOffset"].asReal()); + mWater->set("scaleAbove", windLightLLSD["refractScaleAbove"].asReal()); + mWater->set("scaleBelow", windLightLLSD["refractScaleBelow"].asReal()); + mWater->set("blurMultiplier", windLightLLSD["blurMultiplier"].asReal()); + mWater->set("wave2Dir", windLightLLSD["bigWaveDirectionX"].asReal(), + windLightLLSD["bigWaveDirectionY"].asReal()); + mWater->set("wave1Dir", windLightLLSD["littleWaveDirectionX"].asReal(), + windLightLLSD["littleWaveDirectionY"].asReal()); + mWaterNormal->parseUUID(windLightLLSD["normalMapTexture"].asUUID().asString(), mWaterNormal); + + mSky->setSunAngle(windLightLLSD["sunMoonPosition"].asReal()); + mSky->setEastAngle(windLightLLSD["eastAngle"].asReal()); + + mSky->set("sunlight_color", + windLightLLSD["sunMoonColorX"].asReal() * 3.0f, + windLightLLSD["sunMoonColorY"].asReal() * 3.0f, + windLightLLSD["sunMoonColorZ"].asReal() * 3.0f, + windLightLLSD["sunMoonColorW"].asReal() * 3.0f); + + mSky->set("ambient", + windLightLLSD["ambientX"].asReal() * 3.0f, + windLightLLSD["ambientY"].asReal() * 3.0f, + windLightLLSD["ambientZ"].asReal() * 3.0f, + windLightLLSD["ambientW"].asReal() * 3.0f); + + mSky->set("blue_horizon", + windLightLLSD["horizonX"].asReal() * 2.0f, + windLightLLSD["horizonY"].asReal() * 2.0f, + windLightLLSD["horizonZ"].asReal() * 2.0f, + windLightLLSD["horizonW"].asReal() * 2.0f); + + mSky->set("blue_density", + windLightLLSD["blueDensityX"].asReal(), + windLightLLSD["blueDensityY"].asReal(), + windLightLLSD["blueDensityZ"].asReal(), + 1.0); + + mSky->set("haze_horizon", + windLightLLSD["hazeHorizon"].asReal(), + windLightLLSD["hazeHorizon"].asReal(), + windLightLLSD["hazeHorizon"].asReal(), + 1.f); + + mSky->set("haze_density", + windLightLLSD["hazeDensity"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("cloud_shadow", + windLightLLSD["cloudCoverage"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("density_multiplier", + windLightLLSD["densityMultiplier"].asReal() / 1000.0f, + 0.f, 0.f, 1.f); + + mSky->set("distance_multiplier", + windLightLLSD["distanceMultiplier"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("max_y", + windLightLLSD["maxAltitude"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("cloud_color", + windLightLLSD["cloudColorX"].asReal(), + windLightLLSD["cloudColorY"].asReal(), + windLightLLSD["cloudColorZ"].asReal(), + windLightLLSD["cloudColorW"].asReal()); + + mSky->set("cloud_pos_density1", + windLightLLSD["cloudXYDensityX"].asReal(), + windLightLLSD["cloudXYDensityY"].asReal(), + windLightLLSD["cloudXYDensityZ"].asReal(), + 1.f); + + mSky->set("cloud_pos_density2", + windLightLLSD["cloudDetailXYDensityX"].asReal(), + windLightLLSD["cloudDetailXYDensityY"].asReal(), + windLightLLSD["cloudDetailXYDensityZ"].asReal(), + 1.f); + + mSky->set("cloud_scale", + windLightLLSD["cloudScale"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("gamma", + windLightLLSD["sceneGamma"].asReal(), + 0.f, 0.f, 1.f); + + mSky->set("glow", + (2 - windLightLLSD["sunGlowSize"].asReal()) * 20, + 0.f, + -windLightLLSD["sunGlowFocus"].asReal() * 5, + 1.f); + + mSky->setCloudScrollX(windLightLLSD["cloudScrollX"].asReal() + 10.0f); + mSky->setCloudScrollY(windLightLLSD["cloudScrollY"].asReal() + 10.0f); + + mSky->setEnableCloudScrollX(!windLightLLSD["cloudScrollXLock"].asBoolean()); + mSky->setEnableCloudScrollY(!windLightLLSD["cloudScrollYLock"].asBoolean()); + + mSky->setStarBrightness(windLightLLSD["starBrightness"].asReal()); + + mSky->set("fade", windLightLLSD["fade"].asReal()); + + WLFloaterManager::mMinAltParamList[windLightLLSD["Name"].asString()] = windLightLLSD["minEffectiveAltitude"].asReal(); + WLFloaterManager::mMaxAltParamList[windLightLLSD["Name"].asString()] = windLightLLSD["maxEffectiveAltitude"].asReal(); + WLFloaterManager::mFadeParamList[windLightLLSD["Name"].asString()] = windLightLLSD["fade"].asReal(); + + WLFloaterManager::mWLParamList[windLightLLSD["Name"].asString()] = mSky; + WLFloaterManager::mWaterParamList[windLightLLSD["Name"].asString()] = mWater; + WLFloaterManager::mWaterNormalParamList[windLightLLSD["Name"].asString()] = mWaterNormal; + } + WLFloaterManager::UpdateFloater(); +} + +//If we get back an error (not found, etc...), handle it here +void retrieveWindlightSettings::error(U32 status, const std::string& reason) +{ + LL_INFOS("Inventory") << "retrieveWindlightSettings::error " + << status << ": " << reason << LL_ENDL; +} \ No newline at end of file diff --git a/linden/indra/llmedia/llmediaimplregister.h b/linden/indra/newview/wlretrievesettings.h similarity index 67% rename from linden/indra/llmedia/llmediaimplregister.h rename to linden/indra/newview/wlretrievesettings.h index 51912742f..d75d0d16e 100644 --- a/linden/indra/llmedia/llmediaimplregister.h +++ b/linden/indra/newview/wlretrievesettings.h @@ -1,6 +1,6 @@ -/** - * @file llmediaimplregister.h - * @brief Allow impls to register themselves with the impl factory +/** + * @file wlfloaterwindlightsend.h + * @brief WLFloaterWindLightSend class definition * * $LicenseInfo:firstyear=2007&license=viewergpl$ * @@ -30,31 +30,30 @@ * $/LicenseInfo$ */ -#ifndef LLIMEDIAIMPLREGISTER_H -#define LLIMEDIAIMPLREGISTER_H - -#include <string> +/* + * Menu for adjusting the atmospheric settings of the world + */ -#include "llmediaimplfactory.h" -/////////////////////////////////////////////////////////////////////////////// -// -class LLMediaImplRegister -{ - public: - LLMediaImplRegister( std::string impl_name, LLMediaImplMaker* impl_maker ) : - mImplName( impl_name ) - { - LLMediaImplFactory::getInstance()->registerImpl( impl_name, impl_maker ); - }; +#include <string> +#include "llwlparamset.h" +#include "llwaterparamset.h" +#include "lluuid.h" - std::string getImplName() - { - return mImplName; - }; +class LLSD; +class LLTimer; +class LLUUID; +class LLWaterParamSet; +class LLWLParamSet; - private: - std::string mImplName; -}; -#endif // LLIMEDIAIMPLREGISTER_H +/// Menuing system for all of windlight's functionality +class retrieveWindlightSettings: public LLHTTPClient::Responder +{ +public: + retrieveWindlightSettings(const LLSD& request_sd) : mRequestSD(request_sd) {}; + void result(const LLSD& content); + void error(U32 status, const std::string& reason); +protected: + LLSD mRequestSD; +}; \ No newline at end of file diff --git a/linden/indra/newview/wlsettingsmanager.cpp b/linden/indra/newview/wlsettingsmanager.cpp new file mode 100644 index 000000000..c0a07e1fb --- /dev/null +++ b/linden/indra/newview/wlsettingsmanager.cpp @@ -0,0 +1,253 @@ +/** +* @file wlfloaterwindlightsend.cpp +* @brief WLFloaterWindLightSend class definition +* +* $LicenseInfo:firstyear=2007&license=viewergpl$ +* +* Copyright (c) 2007-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterwindlight.h" + +#include "pipeline.h" +#include "llsky.h" + +#include "llsliderctrl.h" +#include "llmultislider.h" +#include "llmultisliderctrl.h" +#include "llspinctrl.h" +#include "llcheckboxctrl.h" +#include "lluictrlfactory.h" +#include "llviewercamera.h" +#include "llcombobox.h" +#include "lllineeditor.h" +#include "llfloaterdaycycle.h" +#include "lltabcontainer.h" +#include "llboost.h" + +#include "llagent.h" +#include "llinventorymodel.h" +#include "llviewerinventory.h" + +#include "v4math.h" +#include "llviewerdisplay.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "llsavedsettingsglue.h" + +#include "llwlparamset.h" +#include "llwlparammanager.h" +#include "llwaterparammanager.h" +#include "llpostprocess.h" +#include "hippolimits.h" +#include "wlfloaterwindlightsend.h" +#include "llviewerregion.h" +#include "wlsettingsmanager.h" +#include "lightshare.h" + +#include "linden_common.h" +#include "llviewercontrol.h" +#include "message.h" +#include "meta7windlight.h" +#include "llworld.h" + +#undef max + +const std::string WLSettingsManager::wlWaterPresetName = "(Region settings)"; +const std::string WLSettingsManager::wlSkyPresetName = "(Region settings)"; + +LLTimer* WLSettingsManager::wlIgnoreTimer = new LLTimer(); +bool WLSettingsManager::wlIgnoreRegion = false; +LLWaterParamSet* WLSettingsManager::mWater = NULL; +LLWLParamSet* WLSettingsManager::mSky = NULL; +LLUUID* WLSettingsManager::mWaterNormal = NULL; + +void WLSettingsManager::Apply( LLWLParamSet* Sky, LLWaterParamSet* Water, LLUUID* WaterNormal ) +{ + if( gSavedSettings.getU32("LightShareAllowed") <= WindlightMessage::LIGHTSHARE_NEVER ) + return; + + std::string water = LLWaterParamManager::instance()->mCurParams.mName; + std::string sky = LLWLParamManager::instance()->mCurParams.mName; + + // If they are using region settings already, or LightShare is + // always allowed, just apply the new settings, don't bother asking. + if( gSavedSettings.getU32("LightShareAllowed") == WindlightMessage::LIGHTSHARE_ALWAYS || + (sky == wlSkyPresetName && water == wlWaterPresetName) ) + { + mSky = Sky; + mWater = Water; + mWaterNormal = WaterNormal; + Apply(); + return; + } + + if( !wlignoreTimerHasExpired() ) + { + // The user recently ignored a windlight message, so ignore + // this one too, and restart the timer. + wlrestartIgnoreTimer(); + return; + } + + if(wlIgnoreRegion) + { + // We are ignoring new settings until user enters a new region. + return; + } + + if( gSavedSettings.getU32("LightShareAllowed") == WindlightMessage::LIGHTSHARE_ASK && + mSky == NULL && mWater == NULL) + { + // No most recent, so store this and create notification + // asking the user whether to apply or not. + mSky = Sky; + mWater = Water; + mWaterNormal = WaterNormal; + LLNotifications::instance().add("ConfirmLightShare", LLSD(), LLSD(), + boost::bind(&wlapplyCallback, _1, _2)); + } + else + { + // No new notification (to avoid spamming the user, we do keep the saves from above) + mSky = Sky; + mWater = Water; + mWaterNormal = WaterNormal; + } +} + +// static +bool WLSettingsManager::wlapplyCallback(const LLSD& notification, + const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + + switch(option) + { + case 0:{ + // "Apply" + Apply(); + break; + } + case 1:{ + // "Not Now", ignore until the region stops spamming + wlrestartIgnoreTimer(); + break; + } + case 2:{ + // "Ignore", ignore all until user leaves the region + wlIgnoreRegion = true; + break; + } + } + return false; +} + +//static +void WLSettingsManager::Apply() +{ + LLWaterParamManager* water_mgr = LLWaterParamManager::instance(); + LLWLParamManager* sky_mgr = LLWLParamManager::instance(); + + F32 fade = 0; //Instant + bool error; + fade = mSky->getFloat("fade", error); + + mWater->mName = wlWaterPresetName; + if(fade != 0 && water_mgr->mCurParams.mName == wlWaterPresetName)//Load the settings forcefully the first time + { + LLWaterParamSet oldWset = water_mgr->mCurParams; + //This still needs done so that we update right, but load it to the old + water_mgr->removeParamSet( wlWaterPresetName, false ); + water_mgr->addParamSet( wlWaterPresetName, oldWset ); + water_mgr->savePreset( wlWaterPresetName ); + water_mgr->loadPreset( wlWaterPresetName, true ); + water_mgr->setNormalMapID( *mWaterNormal ); + //Then mix with the new + water_mgr->SetMixTime(mWater, fade); + } + else + { + //Instant if fade is 0 + water_mgr->removeParamSet( wlWaterPresetName, false ); + water_mgr->addParamSet( wlWaterPresetName, *mWater ); + water_mgr->savePreset( wlWaterPresetName ); + water_mgr->loadPreset( wlWaterPresetName, true ); + water_mgr->setNormalMapID( *mWaterNormal ); + } + + mSky->mName = wlSkyPresetName; + if(fade != 0 && sky_mgr->mCurParams.mName == wlSkyPresetName)//Load the settings forcefully the first time + { + LLWLParamSet oldset = sky_mgr->mCurParams; + //This still needs done so that we update right, but load it to the old + sky_mgr->removeParamSet( wlSkyPresetName, true ); + sky_mgr->addParamSet( wlSkyPresetName, oldset ); + sky_mgr->savePreset( wlSkyPresetName ); + sky_mgr->loadPreset( wlSkyPresetName, true ); + //Then mix with the new + sky_mgr->SetMixTime(mSky, fade); + } + else + { + //Instant if fade is 0 + sky_mgr->mAnimator.mIsRunning = false; + sky_mgr->mAnimator.mUseLindenTime = false; + sky_mgr->removeParamSet( wlSkyPresetName, false ); + sky_mgr->addParamSet( wlSkyPresetName, *mSky ); + sky_mgr->savePreset( wlSkyPresetName ); + sky_mgr->loadPreset( wlSkyPresetName, true ); + } + + LLWorld::getInstance()->rebuildClouds(gAgent.getRegion()); + + mSky = NULL; + mWater = NULL; + mWaterNormal = NULL; +} + +// static +void WLSettingsManager::wlresetRegion() +{ + wlIgnoreRegion = false; + LLWorld::getInstance()->rebuildClouds(gAgent.getRegion()); +} + +// static +void WLSettingsManager::wlrestartIgnoreTimer() +{ + F32 time = gSavedSettings.getF32("LightShareIgnoreTimer"); + wlIgnoreTimer->start(); + wlIgnoreTimer->setTimerExpirySec( (time < 0) ? 0 : time ); +} + +// static +bool WLSettingsManager::wlignoreTimerHasExpired() +{ + return wlIgnoreTimer->hasExpired(); +} \ No newline at end of file diff --git a/linden/indra/newview/wlsettingsmanager.h b/linden/indra/newview/wlsettingsmanager.h new file mode 100644 index 000000000..5a0e9e737 --- /dev/null +++ b/linden/indra/newview/wlsettingsmanager.h @@ -0,0 +1,90 @@ +/** + * @file wlfloaterwindlightsend.h + * @brief WLFloaterWindLightSend class definition + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +/* + * Menu for adjusting the atmospheric settings of the world + */ + +#ifndef WINDLIGHTSETTINGSMANAGER_H +#define WINDLIGHTSETTINGSMANAGER_H + +#include <string> +#include "llwlparamset.h" +#include "llwaterparamset.h" +#include "lluuid.h" + +class LLSD; +class LLTimer; +class LLUUID; +class LLWaterParamSet; +class LLWLParamSet; + + +/// Menuing system for all of windlight's functionality +class WLSettingsManager +{ +public: + + static LLTimer* wlIgnoreTimer; + static bool wlIgnoreRegion; + + // Called after the user has entered a new region, to reset the + // "ignore while in this region" state. + static void wlresetRegion(); + + static void Apply( LLWLParamSet* Sky, LLWaterParamSet* Water, LLUUID* WaterNormal ); + + // Callback when the user interacts with the notification. + static bool wlapplyCallback(const LLSD& notification, + const LLSD& response); + + static LLWaterParamSet* mWater; + static LLWLParamSet* mSky; + static LLUUID* mWaterNormal; + +private: + static void Apply(); + + // The name of the water preset where the region settings are stored. + static const std::string wlWaterPresetName; + + // The name of the sky preset where the region settings are stored. + static const std::string wlSkyPresetName; + + // Restart the timer for temporarily ignoring settings. + static void wlrestartIgnoreTimer(); + + // Returns true if the ignore timer has expired (i.e. new settings + // should not be ignored anymore). + static bool wlignoreTimerHasExpired(); +}; +#endif \ No newline at end of file diff --git a/linden/indra/test/lltemplatemessagebuilder_tut.cpp b/linden/indra/test/lltemplatemessagebuilder_tut.cpp index 5b33d0272..9fecc2f90 100644 --- a/linden/indra/test/lltemplatemessagebuilder_tut.cpp +++ b/linden/indra/test/lltemplatemessagebuilder_tut.cpp @@ -35,7 +35,6 @@ #include "linden_common.h" #include "lltut.h" -#include "llapr.h" #include "llmessagetemplate.h" #include "llquaternion.h" #include "lltemplatemessagebuilder.h" @@ -59,7 +58,6 @@ namespace tut static bool init = false; if(! init) { - ll_init_apr(); const F32 circuit_heartbeat_interval=5; const F32 circuit_timeout=100; diff --git a/linden/indra/test/message_tut.cpp b/linden/indra/test/message_tut.cpp index 3fede2608..694db5213 100644 --- a/linden/indra/test/message_tut.cpp +++ b/linden/indra/test/message_tut.cpp @@ -35,7 +35,6 @@ #include "linden_common.h" #include "lltut.h" -#include "llapr.h" #include "llmessageconfig.h" #include "llsdserialize.h" #include "llversionserver.h" @@ -68,7 +67,6 @@ namespace tut static bool init = false; if(!init) { - ll_init_apr(); //init_prehash_data(); init = true; } diff --git a/linden/indra/test/test.cpp b/linden/indra/test/test.cpp index ba81c6e49..b699f74b0 100644 --- a/linden/indra/test/test.cpp +++ b/linden/indra/test/test.cpp @@ -43,8 +43,8 @@ #include "linden_common.h" #include "llerrorcontrol.h" #include "lltut.h" +#include "aiaprpool.h" -#include "apr_pools.h" #include "apr_getopt.h" // the CTYPE_WORKAROUND is needed for linux dev stations that don't @@ -248,17 +248,12 @@ int main(int argc, char **argv) ctype_workaround(); #endif - apr_initialize(); - apr_pool_t* pool = NULL; - if(APR_SUCCESS != apr_pool_create(&pool, NULL)) - { - std::cerr << "Unable to initialize pool" << std::endl; - return 1; - } + LLAPRPool pool; + pool.create(); apr_getopt_t* os = NULL; - if(APR_SUCCESS != apr_getopt_init(&os, pool, argc, argv)) + if(APR_SUCCESS != apr_getopt_init(&os, pool(), argc, argv)) { - std::cerr << "Unable to pool" << std::endl; + std::cerr << "Unable to initialize the arguments for parsing by apr_getopt()." << std::endl; return 1; } @@ -360,6 +355,5 @@ int main(int argc, char **argv) s.close(); } - apr_terminate(); return 0; } diff --git a/linden/indra/test_apps/llplugintest/CMakeLists.txt b/linden/indra/test_apps/llplugintest/CMakeLists.txt new file mode 100644 index 000000000..a6cb74007 --- /dev/null +++ b/linden/indra/test_apps/llplugintest/CMakeLists.txt @@ -0,0 +1,378 @@ +# -*- cmake -*- + +project(llplugintest) + +include(00-Common) +include(FindOpenGL) +include(LLCommon) +include(LLPlugin) +include(Linking) +include(PluginAPI) +include(LLImage) +include(LLMath) +include(LLMessage) +include(LLRender) +include(LLWindow) +include(Glut) +include(Glui) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLMESSAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} +) + +if (DARWIN) + include(CMakeFindFrameworks) + find_library(COREFOUNDATION_LIBRARY CoreFoundation) +endif (DARWIN) + +### demo_plugin + +#set(demo_plugin_SOURCE_FILES +# demo_plugin.cpp +# ) +# +#add_library(demo_plugin +# SHARED +# ${demo_plugin_SOURCE_FILES} +#) +# +#target_link_libraries(demo_plugin +# ${LLPLUGIN_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +# ${PLUGIN_API_WINDOWS_LIBRARIES} +#) +# +#add_dependencies(demo_plugin +# ${LLPLUGIN_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +#) +# +#if (DARWIN) +# # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name +# set_target_properties( +# demo_plugin +# PROPERTIES +# PREFIX "" +# BUILD_WITH_INSTALL_RPATH 1 +# INSTALL_NAME_DIR "@executable_path" +# ) +#endif (DARWIN) + +### plugin_host + +#set(plugin_host_SOURCE_FILES +# plugin_host.cpp +# ) +# +#add_executable(plugin_host +# WIN32 +# ${plugin_host_SOURCE_FILES} +#) +# +#set_target_properties(plugin_host +# PROPERTIES +# WIN32_EXECUTABLE +# FALSE +#) +# +#target_link_libraries(plugin_host +# ${LLPLUGIN_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +# ${PLUGIN_API_WINDOWS_LIBRARIES} +#) +# +#add_dependencies(plugin_host +# demo_plugin +# ${LLPLUGIN_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +#) + +### plugin_process_launcher + +#set(plugin_process_launcher_SOURCE_FILES +# plugin_process_launcher.cpp +# ) +# +#add_executable(plugin_process_launcher +# WIN32 +# ${plugin_process_launcher_SOURCE_FILES} +#) +# +#set_target_properties(plugin_process_launcher +# PROPERTIES +# WIN32_EXECUTABLE +# FALSE +#) +# +#target_link_libraries(plugin_process_launcher +# ${LLPLUGIN_LIBRARIES} +# ${LLMESSAGE_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +# ${PLUGIN_API_WINDOWS_LIBRARIES} +#) +# +#add_dependencies(plugin_process_launcher +# SLPlugin +# demo_plugin +# ${LLPLUGIN_LIBRARIES} +# ${LLMESSAGE_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +#) + +### media_simple_test + +#set(media_simple_test_SOURCE_FILES +# media_simple_test.cpp +# ) +# +#add_executable(media_simple_test +# WIN32 +# ${media_simple_test_SOURCE_FILES} +#) +# +#add_dependencies(media_simple_test copy_win_libs) +# +#set_target_properties(media_simple_test +# PROPERTIES +# WIN32_EXECUTABLE +# FALSE +#) +# +#target_link_libraries(media_simple_test +# ${GLUT_LIBRARY} +# ${OPENGL_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +#) + +### media_plugin_test + +#set(media_plugin_test_SOURCE_FILES +# media_plugin_test.cpp +# ) +# +#add_executable(media_plugin_test +# WIN32 +# ${media_plugin_test_SOURCE_FILES} +#) +# +#set_target_properties(media_plugin_test +# PROPERTIES +# WIN32_EXECUTABLE +# FALSE +#) +# +#target_link_libraries(media_plugin_test +# ${GLUT_LIBRARY} +# ${OPENGL_LIBRARIES} +# ${LLPLUGIN_LIBRARIES} +# ${LLMESSAGE_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +# ${PLUGIN_API_WINDOWS_LIBRARIES} +#) +# +#add_dependencies(media_plugin_test +# copy_win_libs +# SLPlugin +# demo_media_plugin +# ${LLPLUGIN_LIBRARIES} +# ${LLMESSAGE_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +#) + +### demo_media_plugin + +#set(demo_media_plugin_SOURCE_FILES +# demo_media_plugin.cpp +# ) +# +#add_library(demo_media_plugin +# SHARED +# ${demo_media_plugin_SOURCE_FILES} +#) +# +#target_link_libraries(demo_media_plugin +# ${LLPLUGIN_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +# ${PLUGIN_API_WINDOWS_LIBRARIES} +#) +# +#add_dependencies(demo_media_plugin +# ${LLPLUGIN_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +#) +# +#if (DARWIN) +# # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name +# set_target_properties( +# demo_media_plugin +# PROPERTIES +# PREFIX "" +# BUILD_WITH_INSTALL_RPATH 1 +# INSTALL_NAME_DIR "@executable_path" +# ) +#endif (DARWIN) + +### demo_media_plugin_2 + +#set(demo_media_plugin_2_SOURCE_FILES +# demo_media_plugin_2.cpp +# ) +# +#add_library(demo_media_plugin_2 +# SHARED +# ${demo_media_plugin_2_SOURCE_FILES} +#) +# +#target_link_libraries(demo_media_plugin_2 +# ${LLPLUGIN_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +# ${PLUGIN_API_WINDOWS_LIBRARIES} +#) +# +#add_dependencies(demo_media_plugin_2 +# ${LLPLUGIN_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +#) +# +#if (DARWIN) +# # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name +# set_target_properties( +# demo_media_plugin_2 +# PROPERTIES +# PREFIX "" +# BUILD_WITH_INSTALL_RPATH 1 +# INSTALL_NAME_DIR "@executable_path" +# ) +#endif (DARWIN) + +### llmediaplugintest + +set(llmediaplugintest_SOURCE_FILES + llmediaplugintest.cpp + llmediaplugintest.h + bookmarks.txt + ) + +add_executable(llmediaplugintest + WIN32 + ${llmediaplugintest_SOURCE_FILES} +) + +set_target_properties(llmediaplugintest + PROPERTIES + WIN32_EXECUTABLE + FALSE +) + +target_link_libraries(llmediaplugintest + ${GLUT_LIBRARY} + ${GLUI_LIBRARY} + ${OPENGL_LIBRARIES} + ${LLPLUGIN_LIBRARIES} + ${LLMESSAGE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${PLUGIN_API_WINDOWS_LIBRARIES} +) + +if (DARWIN) + # The testbed needs to use a couple of CoreFoundation calls now, to deal with being a bundled app. + target_link_libraries(llmediaplugintest + ${COREFOUNDATION_LIBRARY} + ) +endif (DARWIN) + +add_dependencies(llmediaplugintest + copy_win_libs + SLPlugin + media_plugin_quicktime + media_plugin_webkit + media_plugin_example + ${LLPLUGIN_LIBRARIES} + ${LLMESSAGE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + +# turn off weird GLUI pragma +add_definitions(-DGLUI_NO_LIB_PRAGMA) + +if (DARWIN OR LINUX) + # glui.h contains code that triggers the "overloaded-virtual" warning in gcc. + set_source_files_properties(llmediaplugintest.cpp PROPERTIES COMPILE_FLAGS "-Wno-overloaded-virtual") +endif (DARWIN OR LINUX) + +# Gather build products of the various dependencies into the build directory for the testbed. + +if (DARWIN) + # path inside the app bundle where we'll need to copy plugins and other related files + set(PLUGINS_DESTINATION_DIR + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llmediaplugintest.app/Contents/Resources + ) + + # create the Contents/Resources directory + add_custom_command( + TARGET llmediaplugintest POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + make_directory + ${PLUGINS_DESTINATION_DIR} + COMMENT "Creating Resources directory in app bundle." + ) +else (DARWIN) + set(PLUGINS_DESTINATION_DIR + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/ + ) +endif (DARWIN) + +get_target_property(BUILT_SLPLUGIN SLPlugin LOCATION) +add_custom_command(TARGET llmediaplugintest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_SLPLUGIN} ${PLUGINS_DESTINATION_DIR} + DEPENDS ${BUILT_SLPLUGIN} +) + +if (DARWIN OR WINDOWS) + get_target_property(BUILT_WEBKIT_PLUGIN media_plugin_webkit LOCATION) + add_custom_command(TARGET llmediaplugintest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_WEBKIT_PLUGIN} ${PLUGINS_DESTINATION_DIR} + DEPENDS ${BUILT_WEBKIT_PLUGIN} + ) + + get_target_property(BUILT_QUICKTIME_PLUGIN media_plugin_quicktime LOCATION) + add_custom_command(TARGET llmediaplugintest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_QUICKTIME_PLUGIN} ${PLUGINS_DESTINATION_DIR} + DEPENDS ${BUILT_QUICKTIME_PLUGIN} + ) + + get_target_property(BUILT_EXAMPLE_PLUGIN media_plugin_example LOCATION) + add_custom_command(TARGET llmediaplugintest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_EXAMPLE_PLUGIN} ${PLUGINS_DESTINATION_DIR} + DEPENDS ${BUILT_EXAMPLE_PLUGIN} + ) + + # copy over bookmarks file if llmediaplugintest gets built + get_target_property(BUILT_LLMEDIAPLUGINTEST llmediaplugintest LOCATION) + add_custom_command(TARGET llmediaplugintest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${CMAKE_CURRENT_BINARY_DIR}/ + DEPENDS ${BUILT_LLMEDIAPLUGINTEST} + ) + # also copy it to the same place as SLPlugin, which is what the mac wants... + add_custom_command(TARGET llmediaplugintest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${PLUGINS_DESTINATION_DIR} + DEPENDS ${BUILT_LLMEDIAPLUGINTEST} + ) +endif (DARWIN OR WINDOWS) + +if (DARWIN) + add_custom_command(TARGET llmediaplugintest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${PLUGINS_DESTINATION_DIR} + DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib + ) +endif (DARWIN) + + diff --git a/linden/indra/test_apps/llplugintest/bookmarks.txt b/linden/indra/test_apps/llplugintest/bookmarks.txt new file mode 100644 index 000000000..796cc5d1b --- /dev/null +++ b/linden/indra/test_apps/llplugintest/bookmarks.txt @@ -0,0 +1,28 @@ +# format is description, url (don't put ',' chars in description :) +# if no ',' found, whole line is used for both description and url +(WK) Google Home Page,http://www.google.com +(WK) BBC News Home Page,http://news.bbc.co.uk +(WK) Second Life,http://secondlife.com +(WK) WebKit Home ,http://www.webkit.org +(WK) Yahoo News,http://news.yahoo.com +(WK) Canvas Paint (DHTML version of MS Paint),http://www.canvaspaint.org +(WK) DHTML Lemmings!,http://www.elizium.nu/scripts/lemmings/ +(WK) DHTML graphics demos,http://www.dhteumeuleu.com/ +(WK) Neat Javascript 3D,http://gyu.que.jp/jscloth/ +(QT) Local sample,file:///C|/Program Files/QuickTime/Sample.mov +(QT) Movie - Watchmen Trailer,http://movies.apple.com/movies/wb/watchmen/watchmen-tlr2_480p.mov +(QT) Movie - Transformers - Revenge of the Fallen,http://movies.apple.com/movies/paramount/transformers2/transformersrevengeofthefallen-tlr1_h.320.mov +(QT) Movie - Terminator Salvation,http://movies.apple.com/movies/wb/terminatorsalvation/terminatorsalvation-tlr3_h.320.mov +(QT) Movie - Angels and Demons,http://movies.apple.com/movies/sony_pictures/angelsanddemons/angelsanddemons-video_h.320.mov +(QT) Movie - Sin City Trailer,http://movies.apple.com/movies/miramax/sin_city/sin_city_480.mov +(QT) Movie - The Incredibles Trailer,http://movies.apple.com/movies/disney/the_incredibles/the_incredibles-tlr_a480.mov +(QT) Movie - Streaming Apple Event,http://stream.qtv.apple.com/events/mar/0903lajkszg/m_090374535329zdwg_650_ref.mov +(QT) Movie - MPEG-4 from Amazon S3,http://s3.amazonaws.com/callum-linden/flashdemo/interactive_flash_demo.mp4 +(QT) Movie - Star Trek,http://movies.apple.com/movies/paramount/star_trek/startrek-tlr3_h.320.mov +(QT) Movie - Ice Age 3,http://movies.apple.com/movies/fox/ice_age_iii/iceage3-tlrd_h.320.mov +(QT) Movie - AstroBoy,http://movies.apple.com/movies/summit/astroboy/astroboy-tsr_h.320.mov +(QT) Movie - Ante Up,http://movies.apple.com/movies/independent/anteup/anteup_h.320.mov +(QT) Movie - Every Little Step,http://movies.apple.com/movies/sony/everylittlestep/everylittlestep-clip_h.320.mov +(QT) Movie - The Informers,http://movies.apple.com/movies/independent/theinformers/theinformers_h.320.mov +(QT) Animated GIF,http://upload.wikimedia.org/wikipedia/commons/4/44/Optical.greysquares.arp-animated.gif +(QT) Apple Text Descriptors,http://ubrowser.com/tmp/apple_text.txt diff --git a/linden/indra/test_apps/llplugintest/demo_media_plugin.cpp b/linden/indra/test_apps/llplugintest/demo_media_plugin.cpp new file mode 100644 index 000000000..89e15fd72 --- /dev/null +++ b/linden/indra/test_apps/llplugintest/demo_media_plugin.cpp @@ -0,0 +1,472 @@ +/** + * @file demo_plugin.cpp + * @brief Test plugin to be loaded by the llplugin testbed. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" + +// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint + +class DemoMediaPlugin +{ +public: + + static int init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); + +private: + DemoMediaPlugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~DemoMediaPlugin(); + + static void staticReceiveMessage(const char *message_string, void **user_data); + void receiveMessage(const char *message_string); + void sendMessage(const LLPluginMessage &message); + void setDirty(int left, int top, int right, int bottom); + + LLPluginInstance::sendMessageFunction mHostSendFunction; + void *mHostUserData; + bool mDeleteMe; + + class SharedSegmentInfo + { + public: + void *mAddress; + size_t mSize; + }; + + typedef std::map<std::string, SharedSegmentInfo> SharedSegmentMap; + + SharedSegmentMap mSharedSegments; + +public: + + void clear(void) + { +// return; + + if(mPixels != NULL) + { + for( int y = 0; y < mHeight; ++y ) + { + unsigned char *row = mPixels + ( y * mTextureWidth * mDepth); + for(int x = 0; x < mWidth; ++x) + { + unsigned char *pixel = row + (x * mDepth); + if(0) + { + pixel[0] = 0x20; + pixel[1] = 0x20; + pixel[2] = 0x20; + } + else + { + pixel[0] = rand() % 0x40; + pixel[1] = rand() % 0x40; + pixel[2] = rand() % 0x40; + } + } + } + + setDirty(0, 0, mWidth, mHeight); + } + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void update() + { + const time_t interval = 5; + static time_t last_time = time( NULL ); + time_t cur_time = time( NULL ); + + if ( cur_time - last_time > interval ) + { + clear(); + + last_time = cur_time; + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ) + { + // make sure we don't write outside the buffer + if((x < 0) || (x >= mWidth) || (y < 0) || (y >= mHeight)) + return; + + if(mPixels != NULL) + { + unsigned char *pixel = mPixels; + pixel += y * mTextureWidth * mDepth; // row offset + pixel += (x * mDepth); // columm offset + pixel[0] = b; + pixel[1] = g; + pixel[2] = r; + + setDirty(x, y, x+1, y+1); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseDown( int x, int y ) + { + write_pixel( x, y, 0xff, 0x00, 0x00 ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseUp( int x, int y ) + { + write_pixel( x, y, 0xff, 0xff, 0x00 ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseMove( int x, int y ) + { + write_pixel( x , y , 0xff, 0x00, 0xff ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyPress( unsigned char key ) + { + }; + +private: + unsigned char* mPixels; + int mWidth; + int mHeight; + int mTextureWidth; + int mTextureHeight; + int mDepth; +}; + +int DemoMediaPlugin::init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + DemoMediaPlugin *self = new DemoMediaPlugin(host_send_func, host_user_data); + *plugin_send_func = staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} + + +DemoMediaPlugin::DemoMediaPlugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) +{ + std::cerr << "DemoMediaPlugin constructor" << std::endl; + + mHostSendFunction = host_send_func; + mHostUserData = host_user_data; + mDeleteMe = false; +} + +DemoMediaPlugin::~DemoMediaPlugin() +{ + std::cerr << "DemoMediaPlugin destructor" << std::endl; +} + +void DemoMediaPlugin::staticReceiveMessage(const char *message_string, void **user_data) +{ + DemoMediaPlugin *self = (DemoMediaPlugin*)*user_data; + + if(self != NULL) + { + self->receiveMessage(message_string); + + // If the plugin has processed the delete message, delete it. + if(self->mDeleteMe) + { + delete self; + *user_data = NULL; + } + } +} + +void DemoMediaPlugin::receiveMessage(const char *message_string) +{ +// std::cerr << "DemoMediaPlugin::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + // Normally a plugin would only specify one of these two subclasses, but this is a demo... + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; + message.setValueLLSD("versions", versions); + sendMessage(message); + + // Plugin gets to decide the texture parameters to use. + mDepth = 3; + + message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + message.setValueS32("depth", mDepth); + message.setValueU32("internalformat", GL_RGB); + message.setValueU32("format", GL_RGB); + message.setValueU32("type", GL_UNSIGNED_BYTE); + message.setValueBoolean("coords_opengl", false); // true == use OpenGL-style coordinates, false == (0,0) is upper left. + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + update(); + } + else if(message_name == "shutdown") + { + sendMessage(LLPluginMessage("base", "shutdown_response")); + + mDeleteMe = true; + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = (void*)message_in.getValueU32("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + + + std::cerr << "DemoMediaPlugin::receiveMessage: shared memory added, name: " << name + << ", size: " << info.mSize + << ", address: " << info.mAddress + << std::endl; + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + + std::cerr << "DemoMediaPlugin::receiveMessage: shared memory remove, name = " << name << std::endl; + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + } + mSharedSegments.erase(iter); + } + else + { + std::cerr << "DemoMediaPlugin::receiveMessage: unknown shared memory region!" << std::endl; + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { + std::cerr << "DemoMediaPlugin::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + std::cerr << "Got size change, new size is " << width << " by " << height << std::endl; + std::cerr << " texture size is " << texture_width << " by " << texture_height << std::endl; + + mPixels = (unsigned char*)iter->second.mAddress; + mWidth = width; + mHeight = height; + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + clear(); + } + } + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); +// std::string modifiers = message.getValue("modifiers"); + +// std::cerr << "DemoMediaPlugin::receiveMessage: mouse event \"" << event +// << "\", coords " << x << ", " << y +// << std::endl; + + if(event == "down") + { + mouseDown(x, y); + } + else if(event == "up") + { + mouseUp(x, y); + } + else if(event == "move") + { + mouseMove(x, y); + } + } + else + { + std::cerr << "DemoMediaPlugin::receiveMessage: unknown media message: " << message_string << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) + { + if(message_name == "focus") + { + // foo = message_in.getValueBoolean("focused"); + } + else if(message_name == "clear_cache") + { + } + else if(message_name == "clear_cookies") + { + } + else if(message_name == "enable_cookies") + { + // foo = message_in.getValueBoolean("enable"); + } + else if(message_name == "proxy_setup") + { + // foo = message_in.getValueBoolean("enable"); + // bar = message_in.getValue("host"); + // baz = message_in.getValueS32("port"); + } + else if(message_name == "browse_stop") + { + } + else if(message_name == "browse_reload") + { + // foo = message_in.getValueBoolean("ignore_cache"); + } + else if(message_name == "browse_forward") + { + } + else if(message_name == "browse_back") + { + } + else if(message_name == "set_status_redirect") + { + // foo = message_in.getValueS32("code"); + // bar = message_in.getValue("url"); + } + else + { + std::cerr << "DemoMediaPlugin::receiveMessage: unknown media_browser message: " << message_string << std::endl; + } + } + else + { + std::cerr << "DemoMediaPlugin::receiveMessage: unknown message class: " << message_class << std::endl; + } + + } +} + +void DemoMediaPlugin::sendMessage(const LLPluginMessage &message) +{ + std::string output = message.generate(); + mHostSendFunction(output.c_str(), &mHostUserData); +} + +void DemoMediaPlugin::setDirty(int left, int top, int right, int bottom) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated"); + + message.setValueS32("left", left); + message.setValueS32("top", top); + message.setValueS32("right", right); + message.setValueS32("bottom", bottom); + + sendMessage(message); +} + + +extern "C" +{ +#ifdef WIN32 + __declspec(dllexport) +#endif + int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); +} + +int +#ifdef WIN32 + __declspec(dllexport) +#endif + LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + return DemoMediaPlugin::init(host_send_func, host_user_data, plugin_send_func, plugin_user_data); +} + +#ifdef WIN32 +int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* params ) +{ + return 1; +} +#endif diff --git a/linden/indra/test_apps/llplugintest/demo_media_plugin_2.cpp b/linden/indra/test_apps/llplugintest/demo_media_plugin_2.cpp new file mode 100644 index 000000000..7a76f7405 --- /dev/null +++ b/linden/indra/test_apps/llplugintest/demo_media_plugin_2.cpp @@ -0,0 +1,578 @@ +/** + * @file demo_plugin.cpp + * @brief Test plugin to be loaded by the llplugin testbed. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" + +// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint + +class DemoMediaPlugin2 +{ +public: + + static int init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); + +private: + DemoMediaPlugin2(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~DemoMediaPlugin2(); + + static void staticReceiveMessage(const char *message_string, void **user_data); + void receiveMessage(const char *message_string); + void sendMessage(const LLPluginMessage &message); + void setDirty(int left, int top, int right, int bottom); + + LLPluginInstance::sendMessageFunction mHostSendFunction; + void *mHostUserData; + bool mDeleteMe; + + class SharedSegmentInfo + { + public: + void *mAddress; + size_t mSize; + }; + + typedef std::map<std::string, SharedSegmentInfo> SharedSegmentMap; + + SharedSegmentMap mSharedSegments; + +public: + void updatePixels(void) + { + if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 ) + return; + + if ( mPixels == 0 ) + return; + + if ( mFirstTime ) + { + // now we have a valid width/height - we can initialize positions + for( int n = 0; n < NumObjects; ++n ) + { + mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 ); + mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 ); + + mColorR[ n ] = rand() % 0xa0 + 0x60; + mColorG[ n ] = rand() % 0xa0 + 0x60; + mColorB[ n ] = rand() % 0xa0 + 0x60; + + mXInc[ n ] = 0; + while ( mXInc[ n ] == 0 ) + mXInc[ n ] = rand() % 7 - 3; + + mYInc[ n ] = 0; + while ( mYInc[ n ] == 0 ) + mYInc[ n ] = rand() % 9 - 4; + + mBlockSize[ n ] = rand() % 0x16 + 0x04; + }; + + delete [] mBackgroundPixels; + + mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ]; + + mFirstTime = false; + }; + + if ( time( NULL ) > mLastUpdateTime + 3 ) + { + const int num_squares = rand() % 20 + 4; + int sqr1_r = rand() % 0x80 + 0x20; + int sqr1_g = rand() % 0x80 + 0x20; + int sqr1_b = rand() % 0x80 + 0x20; + int sqr2_r = rand() % 0x80 + 0x20; + int sqr2_g = rand() % 0x80 + 0x20; + int sqr2_b = rand() % 0x80 + 0x20; + + for ( int y1 = 0; y1 < num_squares; ++y1 ) + { + for ( int x1 = 0; x1 < num_squares; ++x1 ) + { + int px_start = mWidth * x1 / num_squares; + int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares; + int py_start = mHeight * y1 / num_squares; + int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares; + + for( int y2 = py_start; y2 < py_end; ++y2 ) + { + for( int x2 = px_start; x2 < px_end; ++x2 ) + { + int rowspan = mWidth * mDepth; + + if ( ( y1 % 2 ) ^ ( x1 % 2 ) ) + { + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b; + } + else + { + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g; + mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b; + }; + }; + }; + }; + }; + + time( &mLastUpdateTime ); + }; + + memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth ); + + for( int n = 0; n < NumObjects; ++n ) + { + if ( rand() % 50 == 0 ) + { + mXInc[ n ] = 0; + while ( mXInc[ n ] == 0 ) + mXInc[ n ] = rand() % 7 - 3; + + mYInc[ n ] = 0; + while ( mYInc[ n ] == 0 ) + mYInc[ n ] = rand() % 9 - 4; + }; + + if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] ) + mXInc[ n ] =- mXInc[ n ]; + + if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] ) + mYInc[ n ] =- mYInc[ n ]; + + mXpos[ n ] += mXInc[ n ]; + mYpos[ n ] += mYInc[ n ]; + + for( int y = 0; y < mBlockSize[ n ]; ++y ) + { + for( int x = 0; x < mBlockSize[ n ]; ++x ) + { + mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ]; + mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ]; + mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ]; + }; + }; + }; + + // TODO: experiment with setDirty to just follow block position + setDirty( 0, 0, mWidth, mHeight ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void update() + { + updatePixels(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ) + { + // make sure we don't write outside the buffer + if((x < 0) || (x >= mWidth) || (y < 0) || (y >= mHeight)) + return; + + if( mBackgroundPixels != NULL) + { + unsigned char *pixel = mBackgroundPixels; + pixel += y * mWidth * mDepth; // row offset + pixel += (x * mDepth); // columm offset + pixel[0] = b; + pixel[1] = g; + pixel[2] = r; + + setDirty(x, y, x+1, y+1); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseDown( int x, int y ) + { + write_pixel( x, y, 0xff, 0x00, 0x00 ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseUp( int x, int y ) + { + write_pixel( x, y, 0xff, 0xff, 0x00 ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseMove( int x, int y ) + { + write_pixel( x , y , 0xff, 0x00, 0xff ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyPress( unsigned char key ) + { + }; + +private: + unsigned char* mPixels; + int mWidth; + int mHeight; + int mTextureWidth; + int mTextureHeight; + int mDepth; + time_t mLastUpdateTime; + bool mFirstTime; + unsigned char* mBackgroundPixels; + enum Constants2 { NumObjects = 20 }; + int mColorR[ NumObjects ]; + int mColorG[ NumObjects ]; + int mColorB[ NumObjects ]; + int mXpos[ NumObjects ]; + int mYpos[ NumObjects ]; + int mXInc[ NumObjects ]; + int mYInc[ NumObjects ]; + int mBlockSize[ NumObjects ]; +}; + +int DemoMediaPlugin2::init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + DemoMediaPlugin2 *self = new DemoMediaPlugin2(host_send_func, host_user_data); + *plugin_send_func = staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} + + +DemoMediaPlugin2::DemoMediaPlugin2(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) +{ + std::cerr << "DemoMediaPlugin2 constructor" << std::endl; + + mHostSendFunction = host_send_func; + mHostUserData = host_user_data; + mDeleteMe = false; + + mLastUpdateTime = 0; + mFirstTime = true; + mLastUpdateTime = 0; + mWidth = 0; + mHeight = 0; + mDepth = 0; + mPixels = 0; + mBackgroundPixels = 0; + + srand( get_clock_count() ) ; +} + +DemoMediaPlugin2::~DemoMediaPlugin2() +{ + std::cerr << "DemoMediaPlugin2 destructor" << std::endl; +} + +void DemoMediaPlugin2::staticReceiveMessage(const char *message_string, void **user_data) +{ + DemoMediaPlugin2 *self = (DemoMediaPlugin2*)*user_data; + + if(self != NULL) + { + self->receiveMessage(message_string); + + // If the plugin has processed the delete message, delete it. + if(self->mDeleteMe) + { + delete self; + *user_data = NULL; + } + } +} + +void DemoMediaPlugin2::receiveMessage(const char *message_string) +{ +// std::cerr << "DemoMediaPlugin2::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + // Normally a plugin would only specify one of these two subclasses, but this is a demo... + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; + message.setValueLLSD("versions", versions); + sendMessage(message); + + // Plugin gets to decide the texture parameters to use. + mDepth = 3; + + message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + message.setValueS32("depth", mDepth); + message.setValueU32("internalformat", GL_RGB); + message.setValueU32("format", GL_RGB); + message.setValueU32("type", GL_UNSIGNED_BYTE); + message.setValueBoolean("coords_opengl", false); // true == use OpenGL-style coordinates, false == (0,0) is upper left. + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + update(); + } + else if(message_name == "shutdown") + { + sendMessage(LLPluginMessage("base", "shutdown_response")); + + mDeleteMe = true; + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = (void*)message_in.getValueU32("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + + + std::cerr << "DemoMediaPlugin2::receiveMessage: shared memory added, name: " << name + << ", size: " << info.mSize + << ", address: " << info.mAddress + << std::endl; + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + + std::cerr << "DemoMediaPlugin2::receiveMessage: shared memory remove, name = " << name << std::endl; + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + } + mSharedSegments.erase(iter); + } + else + { + std::cerr << "DemoMediaPlugin2::receiveMessage: unknown shared memory region!" << std::endl; + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { + std::cerr << "DemoMediaPlugin2::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + std::cerr << "Got size change, new size is " << width << " by " << height << std::endl; + std::cerr << " texture size is " << texture_width << " by " << texture_height << std::endl; + + mPixels = (unsigned char*)iter->second.mAddress; + mWidth = width; + mHeight = height; + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + mFirstTime = true; + updatePixels(); + } + } + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); +// std::string modifiers = message.getValue("modifiers"); + +// std::cerr << "DemoMediaPlugin2::receiveMessage: mouse event \"" << event +// << "\", coords " << x << ", " << y +// << std::endl; + + if(event == "down") + { + mouseDown(x, y); + } + else if(event == "up") + { + mouseUp(x, y); + } + else if(event == "move") + { + mouseMove(x, y); + } + } + else + { + std::cerr << "DemoMediaPlugin2::receiveMessage: unknown media message: " << message_string << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) + { + if(message_name == "focus") + { + // foo = message_in.getValueBoolean("focused"); + } + else if(message_name == "clear_cache") + { + } + else if(message_name == "clear_cookies") + { + } + else if(message_name == "enable_cookies") + { + // foo = message_in.getValueBoolean("enable"); + } + else if(message_name == "proxy_setup") + { + // foo = message_in.getValueBoolean("enable"); + // bar = message_in.getValue("host"); + // baz = message_in.getValueS32("port"); + } + else if(message_name == "browse_stop") + { + } + else if(message_name == "browse_reload") + { + // foo = message_in.getValueBoolean("ignore_cache"); + } + else if(message_name == "browse_forward") + { + } + else if(message_name == "browse_back") + { + } + else if(message_name == "set_status_redirect") + { + // foo = message_in.getValueS32("code"); + // bar = message_in.getValue("url"); + } + else + { + std::cerr << "DemoMediaPlugin2::receiveMessage: unknown media_browser message: " << message_string << std::endl; + } + } + else + { + std::cerr << "DemoMediaPlugin2::receiveMessage: unknown message class: " << message_class << std::endl; + } + + } +} + +void DemoMediaPlugin2::sendMessage(const LLPluginMessage &message) +{ + std::string output = message.generate(); + mHostSendFunction(output.c_str(), &mHostUserData); +} + +void DemoMediaPlugin2::setDirty(int left, int top, int right, int bottom) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated"); + + message.setValueS32("left", left); + message.setValueS32("top", top); + message.setValueS32("right", right); + message.setValueS32("bottom", bottom); + + sendMessage(message); +} + + +extern "C" +{ +#ifdef WIN32 + __declspec(dllexport) +#endif + int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); +} + +int +#ifdef WIN32 + __declspec(dllexport) +#endif + LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + return DemoMediaPlugin2::init(host_send_func, host_user_data, plugin_send_func, plugin_user_data); +} + +#ifdef WIN32 +int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* params ) +{ + return 1; +} +#endif diff --git a/linden/indra/test_apps/llplugintest/demo_plugin.cpp b/linden/indra/test_apps/llplugintest/demo_plugin.cpp new file mode 100644 index 000000000..fd67a5898 --- /dev/null +++ b/linden/indra/test_apps/llplugintest/demo_plugin.cpp @@ -0,0 +1,222 @@ +/** + * @file demo_plugin.cpp + * @brief Test plugin to be loaded by the llplugin testbed. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#ifdef WIN32 +# define WIN32_LEAN_AND_MEAN +# include <winsock2.h> +#include <windows.h> +#endif + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" + +// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint + +class DemoPlugin +{ +public: + + static int init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); + +private: + DemoPlugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~DemoPlugin(); + + static void staticReceiveMessage(const char *message_string, void **user_data); + void receiveMessage(const char *message_string); + void sendMessage(const LLPluginMessage &message); + + LLPluginInstance::sendMessageFunction mHostSendFunction; + void *mHostUserData; + bool mDeleteMe; + + int mSharedSegmentFillValue; + void *mSharedSegmentBase; + size_t mSharedSegmentSize; +}; + +int DemoPlugin::init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + DemoPlugin *self = new DemoPlugin(host_send_func, host_user_data); + *plugin_send_func = staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} + +DemoPlugin::DemoPlugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) +{ + std::cerr << "DemoPlugin constructor" << std::endl; + + mHostSendFunction = host_send_func; + mHostUserData = host_user_data; + mDeleteMe = false; + mSharedSegmentBase = NULL; + mSharedSegmentSize = 0; + mSharedSegmentFillValue = 0; +} + +DemoPlugin::~DemoPlugin() +{ + std::cerr << "DemoPlugin destructor" << std::endl; +} + +void DemoPlugin::staticReceiveMessage(const char *message_string, void **user_data) +{ + DemoPlugin *self = (DemoPlugin*)*user_data; + + if(self != NULL) + { + self->receiveMessage(message_string); + + // If the plugin has processed the delete message, delete it. + if(self->mDeleteMe) + { + delete self; + *user_data = NULL; + } + } +} + +void DemoPlugin::receiveMessage(const char *message_string) +{ +// std::cerr << "DemoPlugin::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == "base") + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + message.setValueLLSD("versions", versions); + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. +// std::cerr << "DemoPlugin::receiveMessage: idle processing" << std::endl; + if(mSharedSegmentBase != NULL) + { + // Fill the shared memory segment + memset(mSharedSegmentBase, mSharedSegmentFillValue, mSharedSegmentSize); + // and increment the fill value + mSharedSegmentFillValue++; + } + } + else if(message_name == "shutdown") + { + sendMessage(LLPluginMessage("base", "shutdown_response")); + + mDeleteMe = true; + } + else if(message_name == "shm_added") + { + // Normally, we would check the name and match it up with something from another message. + // For this test, just fill any segment that comes in. + mSharedSegmentSize = (size_t)message_in.getValueS32("size"); + mSharedSegmentBase = (void*)message_in.getValueU32("address"); + + std::cerr << "DemoPlugin::receiveMessage: shared memory added, name: " << message_in.getValue("name") + << ", size: " << mSharedSegmentSize + << ", address: " << mSharedSegmentBase + << std::endl; + + memset(mSharedSegmentBase, mSharedSegmentFillValue, mSharedSegmentSize); + + } + else if(message_name == "shm_remove") + { + std::cerr << "DemoPlugin::receiveMessage: shared memory remove" << std::endl; + + // Normally, we would check the name and match it up with something from another message. + // For this test, just stop filling the only segment we track. + + mSharedSegmentBase = NULL; + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", message_in.getValue("name")); + sendMessage(message); + } + else + { + std::cerr << "DemoPlugin::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else + { + std::cerr << "DemoPlugin::receiveMessage: unknown message class: " << message_class << std::endl; + } + + } +} + +void DemoPlugin::sendMessage(const LLPluginMessage &message) +{ + std::string output = message.generate(); + mHostSendFunction(output.c_str(), &mHostUserData); +} + + +extern "C" +{ +#ifdef WIN32 + __declspec(dllexport) +#endif + int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); +} + +int +#ifdef WIN32 + __declspec(dllexport) +#endif + LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + return DemoPlugin::init(host_send_func, host_user_data, plugin_send_func, plugin_user_data); +} + +#ifdef WIN32 +int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* params ) +{ + return 1; +} +#endif diff --git a/linden/indra/test_apps/llplugintest/llmediaplugintest.cpp b/linden/indra/test_apps/llplugintest/llmediaplugintest.cpp new file mode 100644 index 000000000..bc3703d57 --- /dev/null +++ b/linden/indra/test_apps/llplugintest/llmediaplugintest.cpp @@ -0,0 +1,2208 @@ +/** + * @file LLMediaPluginTest.cpp + * @brief Primary test application for LLMedia (Separate Process) Plugin system + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "indra_constants.h" + +#include "llapr.h" +#include "llerrorcontrol.h" + +#include <math.h> +#include <iomanip> +#include <sstream> +#include <ctime> + +#include "llmediaplugintest.h" + +#if __APPLE__ + #include <GLUT/glut.h> + #include <CoreFoundation/CoreFoundation.h> +#else + #define FREEGLUT_STATIC + #include "GL/freeglut.h" + #define GLUI_FREEGLUT +#endif + +#if LL_WINDOWS +#pragma warning(disable: 4263) +#pragma warning(disable: 4264) +#endif +#include "glui.h" + + +LLMediaPluginTest* gApplication = 0; +static void gluiCallbackWrapper( int control_id ); + +//////////////////////////////////////////////////////////////////////////////// +// +static bool isTexture( GLuint texture ) +{ + bool result = false; + + // glIsTexture will sometimes return false for real textures... do this instead. + if(texture != 0) + result = true; + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +// +mediaPanel::mediaPanel() +{ + mMediaTextureHandle = 0; + mPickTextureHandle = 0; + mMediaSource = NULL; + mPickTexturePixels = NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +// +mediaPanel::~mediaPanel() +{ + // delete OpenGL texture handles + if ( isTexture( mPickTextureHandle ) ) + { + std::cerr << "remMediaPanel: deleting pick texture " << mPickTextureHandle << std::endl; + glDeleteTextures( 1, &mPickTextureHandle ); + mPickTextureHandle = 0; + } + + if ( isTexture( mMediaTextureHandle ) ) + { + std::cerr << "remMediaPanel: deleting media texture " << mMediaTextureHandle << std::endl; + glDeleteTextures( 1, &mMediaTextureHandle ); + mMediaTextureHandle = 0; + } + + if(mPickTexturePixels) + { + delete mPickTexturePixels; + } + + if(mMediaSource) + { + delete mMediaSource; + } + +} + +//////////////////////////////////////////////////////////////////////////////// +// +LLMediaPluginTest::LLMediaPluginTest( int app_window, int window_width, int window_height ) : + mVersionMajor( 2 ), + mVersionMinor( 0 ), + mVersionPatch( 0 ), + mMaxPanels( 25 ), + mViewportAspect( 0 ), + mAppWindow( app_window ), + mCurMouseX( 0 ), + mCurMouseY( 0 ), + mFuzzyMedia( true ), + mSelectedPanel( 0 ), + mMediaBrowserControlEnableCookies( 0 ), + mMediaBrowserControlBackButton( 0 ), + mMediaBrowserControlForwardButton( 0 ), + mMediaTimeControlVolume( 100 ), + mMediaTimeControlSeekSeconds( 0 ), + mGluiMediaTimeControlWindowFlag( true ), + mGluiMediaBrowserControlWindowFlag( true ), + mMediaBrowserControlBackButtonFlag( true ), + mMediaBrowserControlForwardButtonFlag( true ), + mHomeWebUrl( "http://www.google.com/" ) +{ + // debugging spam + std::cout << std::endl << " GLUT version: " << "3.7.6" << std::endl; // no way to get real version from GLUT + std::cout << std::endl << " GLUI version: " << GLUI_Master.get_version() << std::endl; + std::cout << std::endl << "Media Plugin Test version: " << mVersionMajor << "." << mVersionMinor << "." << mVersionPatch << std::endl; + + // bookmark title + mBookmarks.push_back( std::pair< std::string, std::string >( "--- Bookmarks ---", "" ) ); + + // insert hardcoded URLs here as required for testing + //mBookmarks.push_back( std::pair< std::string, std::string >( "description", "url" ) ); + + // read bookmarks from file. + // note: uses command in ./CmakeLists.txt which copies bookmmarks file from source directory + // to app directory (WITHOUT build configuration dir) (this is cwd in Windows within MSVC) + // For example, test_apps\llplugintest and not test_apps\llplugintest\Release + // This may need to be changed for Mac/Linux builds. + // See https://jira.lindenlab.com/browse/DEV-31350 for large list of media URLs from AGNI + const std::string bookmarks_filename( "bookmarks.txt" ); + std::ifstream file_handle( bookmarks_filename.c_str() ); + if ( file_handle.is_open() ) + { + std::cout << "Reading bookmarks for test" << std::endl; + while( ! file_handle.eof() ) + { + std::string line; + std::getline( file_handle, line ); + if ( file_handle.eof() ) + break; + + if ( line.substr( 0, 1 ) != "#" ) + { + size_t comma_pos = line.find_first_of( ',' ); + if ( comma_pos != std::string::npos ) + { + std::string description = line.substr( 0, comma_pos ); + std::string url = line.substr( comma_pos + 1 ); + mBookmarks.push_back( std::pair< std::string, std::string >( description, url ) ); + } + else + { + mBookmarks.push_back( std::pair< std::string, std::string >( line, line ) ); + }; + }; + }; + std::cout << "Read " << mBookmarks.size() << " bookmarks" << std::endl; + } + else + { + std::cout << "Unable to read bookmarks from file: " << bookmarks_filename << std::endl; + }; + + // initialize linden lab APR module + ll_init_apr(); + + // Set up llerror logging + { + LLError::initForApplication("."); + LLError::setDefaultLevel(LLError::LEVEL_INFO); + //LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG); + } + + // lots of randomness in this app + srand( ( unsigned int )time( 0 ) ); + + // build GUI + makeChrome(); + + // OpenGL initialilzation + glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + glClearDepth( 1.0f ); + glEnable( GL_DEPTH_TEST ); + glEnable( GL_COLOR_MATERIAL ); + glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); + glDepthFunc( GL_LEQUAL ); + glEnable( GL_TEXTURE_2D ); + glDisable( GL_BLEND ); + glColor3f( 1.0f, 1.0f, 1.0f ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); + + // start with a sane view + resetView(); + + // initial media panel + const int num_initial_panels = 1; + for( int i = 0; i < num_initial_panels; ++i ) + { + //addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second ); + addMediaPanel( mHomeWebUrl ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +LLMediaPluginTest::~LLMediaPluginTest() +{ + // delete all media panels + for( int i = 0; i < (int)mMediaPanels.size(); ++i ) + { + remMediaPanel( mMediaPanels[ i ] ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::reshape( int width, int height ) +{ + // update viewport (the active window inside the chrome) + int viewport_x, viewport_y; + int viewport_height, viewport_width; + GLUI_Master.get_viewport_area( &viewport_x, &viewport_y, &viewport_width, &viewport_height ); + mViewportAspect = (float)( viewport_width ) / (float)( viewport_height ); + glViewport( viewport_x, viewport_y, viewport_width, viewport_height ); + + // save these as we'll need them later + mWindowWidth = width; + mWindowHeight = height; + + // adjust size of URL bar so it doesn't get clipped + mUrlEdit->set_w( mWindowWidth - 360 ); + + // GLUI requires this + if ( glutGetWindow() != mAppWindow ) + glutSetWindow( mAppWindow ); + + // trigger re-display + glutPostRedisplay(); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::bindTexture(GLuint texture, GLint row_length, GLint alignment) +{ + glEnable( GL_TEXTURE_2D ); + + glBindTexture( GL_TEXTURE_2D, texture ); + glPixelStorei( GL_UNPACK_ROW_LENGTH, row_length ); + glPixelStorei( GL_UNPACK_ALIGNMENT, alignment ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLMediaPluginTest::checkGLError(const char *name) +{ + bool result = false; + GLenum error = glGetError(); + + if(error != GL_NO_ERROR) + { + // For some reason, glGenTextures is returning GL_INVALID_VALUE... + std::cout << name << " ERROR 0x" << std::hex << error << std::dec << std::endl; + result = true; + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::drawGeometry( int panel ) +{ + // texture coordinates for each panel + GLfloat non_opengl_texture_coords[ 8 ] = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f }; + GLfloat opengl_texture_coords[ 8 ] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f }; + + GLfloat *texture_coords = mMediaPanels[ panel ]->mAppTextureCoordsOpenGL?opengl_texture_coords:non_opengl_texture_coords; + + // base coordinates for each panel + GLfloat base_vertex_pos[ 8 ] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f }; + + // calculate posiitons + const int num_panels = (int)mMediaPanels.size(); + const int num_rows = (int)sqrt( (float)num_panels ); + const int num_cols = num_panels / num_rows; + const int panel_x = ( panel / num_rows ); + const int panel_y = ( panel % num_rows ); + + const float spacing = 0.1f; + const GLfloat offset_x = num_cols * ( 1.0 + spacing ) / 2; + const GLfloat offset_y = num_rows * ( 1.0 + spacing ) / 2; + + // Adjust for media aspect ratios + { + float aspect = 1.0f; + + if(mMediaPanels[ panel ]->mMediaHeight != 0) + { + aspect = (float)mMediaPanels[ panel ]->mMediaWidth / (float)mMediaPanels[ panel ]->mMediaHeight; + } + + if(aspect > 1.0f) + { + // media is wider than it is high -- adjust the top and bottom in + for( int corner = 0; corner < 4; ++corner ) + { + float temp = base_vertex_pos[corner * 2 + 1]; + + if(temp < 0.5f) + temp += 0.5 - (0.5f / aspect); + else + temp -= 0.5 - (0.5f / aspect); + + base_vertex_pos[corner * 2 + 1] = temp; + } + } + else if(aspect < 1.0f) + { + // media is higher than it is wide -- adjust the left and right sides in + for( int corner = 0; corner < 4; ++corner ) + { + float temp = base_vertex_pos[corner * 2]; + + if(temp < 0.5f) + temp += 0.5f - (0.5f * aspect); + else + temp -= 0.5f - (0.5f * aspect); + + base_vertex_pos[corner * 2] = temp; + } + } + } + + glBegin( GL_QUADS ); + for( int corner = 0; corner < 4; ++corner ) + { + glTexCoord2f( texture_coords[ corner * 2 ], texture_coords[ corner * 2 + 1 ] ); + GLfloat x = base_vertex_pos[ corner * 2 ] + panel_x * ( 1.0 + spacing ) - offset_x + spacing / 2.0f; + GLfloat y = base_vertex_pos[ corner * 2 + 1 ] + panel_y * ( 1.0 + spacing ) - offset_y + spacing / 2.0f; + + glVertex3f( x, y, 0.0f ); + }; + glEnd(); +} + +////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::startPanelHighlight( float red, float green, float blue, float line_width ) +{ + glPushAttrib( GL_ALL_ATTRIB_BITS ); + glEnable( GL_POLYGON_OFFSET_FILL ); + glPolygonOffset( -2.5f, -2.5f ); + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + glLineWidth( line_width ); + glColor3f( red, green, blue ); + glDisable( GL_TEXTURE_2D ); +} + +////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::endPanelHighlight() +{ + glPopAttrib(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::draw( int draw_type ) +{ + for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel ) + { + // drawing pick texture + if ( draw_type == DrawTypePickTexture ) + { + // only bother with pick if we have something to render + // Actually, we need to pick even if we're not ready to render. + // Otherwise you can't select and remove a panel which has gone bad. + //if ( mMediaPanels[ panel ]->mReadyToRender ) + { + glMatrixMode( GL_TEXTURE ); + glPushMatrix(); + + // pick texture is a power of 2 so no need to scale + glLoadIdentity(); + + // bind to media texture + glLoadIdentity(); + bindTexture( mMediaPanels[ panel ]->mPickTextureHandle ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + + // draw geometry using pick texture + drawGeometry( panel ); + + glMatrixMode( GL_TEXTURE ); + glPopMatrix(); + }; + } + else + if ( draw_type == DrawTypeMediaTexture ) + { + bool texture_valid = false; + bool plugin_exited = false; + + if(mMediaPanels[ panel ]->mMediaSource) + { + texture_valid = mMediaPanels[ panel ]->mMediaSource->textureValid(); + plugin_exited = mMediaPanels[ panel ]->mMediaSource->isPluginExited(); + } + + // save texture matrix (changes for each panel) + glMatrixMode( GL_TEXTURE ); + glPushMatrix(); + + // only process texture if the media is ready to draw + // (we still want to draw the geometry) + if ( mMediaPanels[ panel ]->mReadyToRender && texture_valid ) + { + // bind to media texture + bindTexture( mMediaPanels[ panel ]->mMediaTextureHandle ); + + if ( mFuzzyMedia ) + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + } + else + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + } + + // scale to fit panel + glScalef( mMediaPanels[ panel ]->mTextureScaleX, + mMediaPanels[ panel ]->mTextureScaleY, + 1.0f ); + }; + + float intensity = plugin_exited?0.25f:1.0f; + + // highlight the selected panel + if ( mSelectedPanel && ( mMediaPanels[ panel ]->mId == mSelectedPanel->mId ) ) + { + startPanelHighlight( intensity, intensity, 0.0f, 5.0f ); + drawGeometry( panel ); + endPanelHighlight(); + } + else + // this panel not able to render yet since it + // doesn't have enough information + if ( !mMediaPanels[ panel ]->mReadyToRender ) + { + startPanelHighlight( intensity, 0.0f, 0.0f, 2.0f ); + drawGeometry( panel ); + endPanelHighlight(); + } + else + // just display a border around the media + { + startPanelHighlight( 0.0f, intensity, 0.0f, 2.0f ); + drawGeometry( panel ); + endPanelHighlight(); + }; + + if ( mMediaPanels[ panel ]->mReadyToRender && texture_valid ) + { + // draw visual geometry + drawGeometry( panel ); + } + + // restore texture matrix (changes for each panel) + glMatrixMode( GL_TEXTURE ); + glPopMatrix(); + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::display() +{ + // GLUI requires this + if ( glutGetWindow() != mAppWindow ) + glutSetWindow( mAppWindow ); + + // start with a clean slate + glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // set up OpenGL view + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glFrustum( -mViewportAspect * 0.04f, mViewportAspect * 0.04f, -0.04f, 0.04f, 0.1f, 50.0f ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, 0.0f ); + glTranslatef( mViewPos[ 0 ], mViewPos[ 1 ], -mViewPos[ 2 ] ); + glMultMatrixf( mViewRotation ); + + // draw pick texture + draw( DrawTypePickTexture ); + + // read colors and get coordinate values + glReadPixels( mCurMouseX, mCurMouseY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, mPixelReadColor ); + + // clear the pick render (otherwise it may depth-fight with the textures rendered later) + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // draw visible geometry + draw( DrawTypeMediaTexture ); + + glutSwapBuffers(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::idle() +{ +// checkGLError("LLMediaPluginTest::idle"); + + // GLUI requires this + if ( glutGetWindow() != mAppWindow ) + glutSetWindow( mAppWindow ); + + // random creation/destruction of panels enabled? + const time_t panel_timeout_time = 5; + if ( mRandomPanelCount ) + { + // time for a change + static time_t last_panel_time = 0; + if ( time( NULL ) - last_panel_time > panel_timeout_time ) + { + if ( rand() % 2 == 0 ) + { + if ( mMediaPanels.size() < 16 ) + { + std::cout << "Randomly adding new panel" << std::endl; + addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second ); + }; + } + else + { + if ( mMediaPanels.size() > 0 ) + { + std::cout << "Deleting selected panel" << std::endl; + remMediaPanel( mSelectedPanel ); + }; + }; + time( &last_panel_time ); + }; + }; + + // random selection of bookmarks enabled? + const time_t bookmark_timeout_time = 5; + if ( mRandomBookmarks ) + { + // time for a change + static time_t last_bookmark_time = 0; + if ( time( NULL ) - last_bookmark_time > bookmark_timeout_time ) + { + // go to a different random bookmark on each panel + for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel ) + { + std::string uri = mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second; + + std::cout << "Random: navigating to : " << uri << std::endl; + + std::string mime_type = mimeTypeFromUrl( uri ); + + if ( mime_type != mMediaPanels[ panel ]->mMimeType ) + { + replaceMediaPanel( mMediaPanels[ panel ], uri ); + } + else + { + mMediaPanels[ panel ]->mMediaSource->loadURI( uri ); + mMediaPanels[ panel ]->mMediaSource->start(); + }; + }; + + time( &last_bookmark_time ); + }; + }; + + // update UI + if ( mSelectedPanel ) + { + // set volume based on slider if we have time media + //if ( mGluiMediaTimeControlWindowFlag ) + //{ + // mSelectedPanel->mMediaSource->setVolume( (float)mMediaTimeControlVolume / 100.0f ); + //}; + + // NOTE: it is absurd that we need cache the state of GLUI controls + // but enabling/disabling controls drags framerate from 500+ + // down to 15. Not a problem for plugin system - only this test + // enable/disable time based UI controls based on type of plugin + if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() ) + { + if ( ! mGluiMediaTimeControlWindowFlag ) + { + mGluiMediaTimeControlWindow->enable(); + mGluiMediaTimeControlWindowFlag = true; + }; + } + else + { + if ( mGluiMediaTimeControlWindowFlag ) + { + mGluiMediaTimeControlWindow->disable(); + mGluiMediaTimeControlWindowFlag = false; + }; + }; + + // enable/disable browser based UI controls based on type of plugin + if ( mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() ) + { + if ( ! mGluiMediaBrowserControlWindowFlag ) + { + mGluiMediaBrowserControlWindow->enable(); + mGluiMediaBrowserControlWindowFlag = true; + }; + } + else + { + if ( mGluiMediaBrowserControlWindowFlag ) + { + mGluiMediaBrowserControlWindow->disable(); + mGluiMediaBrowserControlWindowFlag = false; + }; + }; + + // enable/disable browser back button depending on browser history + if ( mSelectedPanel->mMediaSource->getHistoryBackAvailable() ) + { + if ( ! mMediaBrowserControlBackButtonFlag ) + { + mMediaBrowserControlBackButton->enable(); + mMediaBrowserControlBackButtonFlag = true; + }; + } + else + { + if ( mMediaBrowserControlBackButtonFlag ) + { + mMediaBrowserControlBackButton->disable(); + mMediaBrowserControlBackButtonFlag = false; + }; + }; + + // enable/disable browser forward button depending on browser history + if ( mSelectedPanel->mMediaSource->getHistoryForwardAvailable() ) + { + if ( ! mMediaBrowserControlForwardButtonFlag ) + { + mMediaBrowserControlForwardButton->enable(); + mMediaBrowserControlForwardButtonFlag = true; + }; + } + else + { + if ( mMediaBrowserControlForwardButtonFlag ) + { + mMediaBrowserControlForwardButton->disable(); + mMediaBrowserControlForwardButtonFlag = false; + }; + }; + + // NOTE: This is *very* slow and not worth optimising + updateStatusBar(); + }; + + // update all the panels + for( int panel_index = 0; panel_index < (int)mMediaPanels.size(); ++panel_index ) + { + mediaPanel *panel = mMediaPanels[ panel_index ]; + + // call plugins idle function so it can potentially update itself + panel->mMediaSource->idle(); + + // update each media panel + updateMediaPanel( panel ); + + LLRect dirty_rect; + if ( ! panel->mMediaSource->textureValid() ) + { + //std::cout << "texture invalid, skipping update..." << std::endl; + } + else + if ( panel && + ( panel->mMediaWidth != panel->mMediaSource->getWidth() || + panel->mMediaHeight != panel->mMediaSource->getHeight() ) ) + { + //std::cout << "Resize in progress, skipping update..." << std::endl; + } + else + if ( panel->mMediaSource->getDirty( &dirty_rect ) ) + { + const unsigned char* pixels = panel->mMediaSource->getBitsData(); + if ( pixels && isTexture(panel->mMediaTextureHandle)) + { + int x_offset = dirty_rect.mLeft; + int y_offset = dirty_rect.mBottom; + int width = dirty_rect.mRight - dirty_rect.mLeft; + int height = dirty_rect.mTop - dirty_rect.mBottom; + + if((dirty_rect.mRight <= panel->mTextureWidth) && (dirty_rect.mTop <= panel->mTextureHeight)) + { + // Offset the pixels pointer properly + pixels += ( y_offset * panel->mMediaSource->getTextureDepth() * panel->mMediaSource->getBitsWidth() ); + pixels += ( x_offset * panel->mMediaSource->getTextureDepth() ); + + // set up texture + bindTexture( panel->mMediaTextureHandle, panel->mMediaSource->getBitsWidth() ); + if ( mFuzzyMedia ) + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + } + else + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + }; + + checkGLError("glTexParameteri"); + + if(panel->mMediaSource->getTextureFormatSwapBytes()) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); + checkGLError("glPixelStorei"); + } + + // draw portion that changes into texture + glTexSubImage2D( GL_TEXTURE_2D, 0, + x_offset, + y_offset, + width, + height, + panel->mMediaSource->getTextureFormatPrimary(), + panel->mMediaSource->getTextureFormatType(), + pixels ); + + if(checkGLError("glTexSubImage2D")) + { + std::cerr << " panel ID=" << panel->mId << std::endl; + std::cerr << " texture size = " << panel->mTextureWidth << " x " << panel->mTextureHeight << std::endl; + std::cerr << " media size = " << panel->mMediaWidth << " x " << panel->mMediaHeight << std::endl; + std::cerr << " dirty rect = " << dirty_rect.mLeft << ", " << dirty_rect.mBottom << ", " << dirty_rect.mRight << ", " << dirty_rect.mTop << std::endl; + std::cerr << " texture width = " << panel->mMediaSource->getBitsWidth() << std::endl; + std::cerr << " format primary = 0x" << std::hex << panel->mMediaSource->getTextureFormatPrimary() << std::dec << std::endl; + std::cerr << " format type = 0x" << std::hex << panel->mMediaSource->getTextureFormatType() << std::dec << std::endl; + std::cerr << " pixels = " << (void*)pixels << std::endl; + } + + if(panel->mMediaSource->getTextureFormatSwapBytes()) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); + checkGLError("glPixelStorei"); + } + + panel->mMediaSource->resetDirty(); + + panel->mReadyToRender = true; + } + else + { + std::cerr << "dirty rect is outside current media size, skipping update" << std::endl; + } + }; + }; + }; + + // GLUI requires this + if ( glutGetWindow() != mAppWindow ) + glutSetWindow( mAppWindow ); + + // trigger re-display + glutPostRedisplay(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::windowPosToTexturePos( int window_x, int window_y, + int& media_x, int& media_y, + int& id ) +{ + if ( ! mSelectedPanel ) + { + media_x = 0; + media_y = 0; + id = 0; + return; + }; + + // record cursor poisiton for a readback next frame + mCurMouseX = window_x; + // OpenGL app == coordinate system this way + // NOTE: unrelated to settings in plugin - this + // is just for this app + mCurMouseY = mWindowHeight - window_y; + + // extract x (0..1023, y (0..1023) and id (0..15) from RGB components + unsigned long pixel_read_color_bits = ( mPixelReadColor[ 0 ] << 16 ) | ( mPixelReadColor[ 1 ] << 8 ) | mPixelReadColor[ 2 ]; + int texture_x = pixel_read_color_bits & 0x3ff; + int texture_y = ( pixel_read_color_bits >> 10 ) & 0x3ff; + id = ( pixel_read_color_bits >> 20 ) & 0x0f; + + // scale to size of media (1024 because we use 10 bits for X and Y from 24) + media_x = (int)( ( (float)mSelectedPanel->mMediaWidth * (float)texture_x ) / 1024.0f ); + media_y = (int)( ( (float)mSelectedPanel->mMediaHeight * (float)texture_y ) / 1024.0f ); + + // we assume the plugin uses an inverted coordinate scheme like OpenGL + // if not, the plugin code inverts the Y coordinate for us - we don't need to + media_y = mSelectedPanel->mMediaHeight - media_y; + + if ( media_x > 0 && media_y > 0 ) + { + //std::cout << " mouse coords: " << mCurMouseX << " x " << mCurMouseY << " and id = " << id << std::endl; + //std::cout << "raw texture coords: " << texture_x << " x " << texture_y << " and id = " << id << std::endl; + //std::cout << " media coords: " << media_x << " x " << media_y << " and id = " << id << std::endl; + //std::cout << std::endl; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::selectPanelById( int id ) +{ + for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel ) + { + if ( mMediaPanels[ panel ]->mId == id ) + { + selectPanel(mMediaPanels[ panel ]); + return; + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::selectPanel( mediaPanel* panel ) +{ + if( mSelectedPanel == panel ) + return; + + // turn off volume before we delete it + if( mSelectedPanel && mSelectedPanel->mMediaSource ) + { + mSelectedPanel->mMediaSource->setVolume( 0.0f ); + mSelectedPanel->mMediaSource->setPriority( LLPluginClassMedia::PRIORITY_LOW ); + }; + + mSelectedPanel = panel; + + if( mSelectedPanel && mSelectedPanel->mMediaSource ) + { + mSelectedPanel->mMediaSource->setVolume( (float)mMediaTimeControlVolume / 100.0f ); + mSelectedPanel->mMediaSource->setPriority( LLPluginClassMedia::PRIORITY_NORMAL ); + + if(!mSelectedPanel->mStartUrl.empty()) + { + mUrlEdit->set_text(const_cast<char*>(mSelectedPanel->mStartUrl.c_str()) ); + } + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +mediaPanel* LLMediaPluginTest::findMediaPanel( LLPluginClassMedia* source ) +{ + mediaPanel *result = NULL; + + for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel ) + { + if ( mMediaPanels[ panel ]->mMediaSource == source ) + { + result = mMediaPanels[ panel ]; + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::navigateToNewURI( std::string uri ) +{ + if ( uri.length() ) + { + std::string mime_type = mimeTypeFromUrl( uri ); + + if ( !mSelectedPanel->mMediaSource->isPluginExited() && (mime_type == mSelectedPanel->mMimeType) ) + { + std::cout << "MIME type is the same" << std::endl; + mSelectedPanel->mMediaSource->loadURI( uri ); + mSelectedPanel->mMediaSource->start(); + mBookmarkList->do_selection( 0 ); + } + else + { + std::cout << "MIME type changed or plugin had exited" << std::endl; + replaceMediaPanel( mSelectedPanel, uri ); + mBookmarkList->do_selection( 0 ); + } + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::initUrlHistory( std::string uris ) +{ + if ( uris.length() > 0 ) + { + std::cout << "init URL : " << uris << std::endl; + LLSD historySD; + + char *cstr, *p; + cstr = new char[uris.size()+1]; + strcpy(cstr, uris.c_str()); + const char *DELIMS = " ,;"; + p = strtok(cstr, DELIMS); + while (p != NULL) { + historySD.insert(0, p); + p = strtok(NULL, DELIMS); + } + mSelectedPanel->mMediaSource->initializeUrlHistory(historySD); + delete[] cstr; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::gluiCallback( int control_id ) +{ + if ( control_id == mIdBookmarks ) + { + std::string uri = mBookmarks[ mSelBookmark ].second; + + navigateToNewURI( uri ); + } + else + if ( control_id == mIdUrlEdit) + { + std::string uri = mUrlEdit->get_text(); + + navigateToNewURI( uri ); + } + else + if ( control_id == mIdUrlInitHistoryEdit ) + { + std::string uri = mUrlInitHistoryEdit->get_text(); + + initUrlHistory( uri ); + } + else + if ( control_id == mIdControlAddPanel ) + { + addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second ); + } + else + if ( control_id == mIdControlRemPanel ) + { + remMediaPanel( mSelectedPanel ); + } + else + if ( control_id == mIdDisableTimeout ) + { + // Set the "disable timeout" flag for all active plugins. + for( int i = 0; i < (int)mMediaPanels.size(); ++i ) + { + mMediaPanels[ i ]->mMediaSource->setDisableTimeout(mDisableTimeout); + } + } + else + if ( control_id == mIdControlCrashPlugin ) + { + // send message to plugin and ask it to crash + // (switch out for ReleaseCandidate version :) ) + if(mSelectedPanel && mSelectedPanel->mMediaSource) + { + mSelectedPanel->mMediaSource->crashPlugin(); + } + } + else + if ( control_id == mIdControlHangPlugin ) + { + // send message to plugin and ask it to hang + // (switch out for ReleaseCandidate version :) ) + if(mSelectedPanel && mSelectedPanel->mMediaSource) + { + mSelectedPanel->mMediaSource->hangPlugin(); + } + } + else + if ( control_id == mIdControlExitApp ) + { + // text for exiting plugin system cleanly + delete this; // clean up + exit( 0 ); + } + else + if ( control_id == mIdMediaTimeControlPlay ) + { + if ( mSelectedPanel ) + { + mSelectedPanel->mMediaSource->setLoop( false ); + mSelectedPanel->mMediaSource->start(); + }; + } + else + if ( control_id == mIdMediaTimeControlLoop ) + { + if ( mSelectedPanel ) + { + mSelectedPanel->mMediaSource->setLoop( true ); + mSelectedPanel->mMediaSource->start(); + }; + } + else + if ( control_id == mIdMediaTimeControlPause ) + { + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->pause(); + } + else + if ( control_id == mIdMediaTimeControlStop ) + { + if ( mSelectedPanel ) + { + mSelectedPanel->mMediaSource->stop(); + }; + } + else + if ( control_id == mIdMediaTimeControlSeek ) + { + if ( mSelectedPanel ) + { + // get value from spinner + float seconds_to_seek = mMediaTimeControlSeekSeconds; + mSelectedPanel->mMediaSource->seek( seconds_to_seek ); + mSelectedPanel->mMediaSource->start(); + }; + } + else + if ( control_id == mIdMediaTimeControlRewind ) + { + if ( mSelectedPanel ) + { + mSelectedPanel->mMediaSource->setLoop( false ); + mSelectedPanel->mMediaSource->start(-2.0f); + }; + } + else + if ( control_id == mIdMediaTimeControlFastForward ) + { + if ( mSelectedPanel ) + { + mSelectedPanel->mMediaSource->setLoop( false ); + mSelectedPanel->mMediaSource->start(2.0f); + }; + } + else + if ( control_id == mIdMediaBrowserControlBack ) + { + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->browse_back(); + } + else + if ( control_id == mIdMediaBrowserControlStop ) + { + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->browse_stop(); + } + else + if ( control_id == mIdMediaBrowserControlForward ) + { + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->browse_forward(); + } + else + if ( control_id == mIdMediaBrowserControlHome ) + { + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->loadURI( mHomeWebUrl ); + } + else + if ( control_id == mIdMediaBrowserControlReload ) + { + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->browse_reload( true ); + } + else + if ( control_id == mIdMediaBrowserControlClearCache ) + { + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->clear_cache(); + } + else + if ( control_id == mIdMediaBrowserControlClearCookies ) + { + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->clear_cookies(); + } + else + if ( control_id == mIdMediaBrowserControlEnableCookies ) + { + if ( mSelectedPanel ) + { + if ( mMediaBrowserControlEnableCookies ) + { + mSelectedPanel->mMediaSource->enable_cookies( true ); + } + else + { + mSelectedPanel->mMediaSource->enable_cookies( false ); + } + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::keyboard( int key ) +{ + //if ( key == 'a' || key == 'A' ) + // addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second ); + //else + //if ( key == 'r' || key == 'R' ) + // remMediaPanel( mSelectedPanel ); + //else + //if ( key == 'd' || key == 'D' ) + // dumpPanelInfo(); + //else + if ( key == 27 ) + { + std::cout << "Application finished - exiting..." << std::endl; + delete this; + exit( 0 ); + }; + + mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_DOWN, key, 0 , LLSD()); + mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_UP, key, 0, LLSD()); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::mouseButton( int button, int state, int x, int y ) +{ + if ( button == GLUT_LEFT_BUTTON ) + { + if ( state == GLUT_DOWN ) + { + int media_x, media_y, id; + windowPosToTexturePos( x, y, media_x, media_y, id ); + + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_DOWN, 0, media_x, media_y, 0 ); + } + else + if ( state == GLUT_UP ) + { + int media_x, media_y, id; + windowPosToTexturePos( x, y, media_x, media_y, id ); + + // only select a panel if we're on a panel + // (HACK: strictly speaking this rules out clicking on + // the origin of a panel but that's very unlikely) + if ( media_x > 0 && media_y > 0 ) + { + selectPanelById( id ); + + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_UP, 0, media_x, media_y, 0 ); + }; + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::mousePassive( int x, int y ) +{ + int media_x, media_y, id; + windowPosToTexturePos( x, y, media_x, media_y, id ); + + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, media_x, media_y, 0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::mouseMove( int x, int y ) +{ + int media_x, media_y, id; + windowPosToTexturePos( x, y, media_x, media_y, id ); + + if ( mSelectedPanel ) + mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, media_x, media_y, 0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::makeChrome() +{ + // IDs used by GLUI + int start_id = 0x1000; + + // right side window - geometry manipulators +#if __APPLE__ + // the Apple GLUT implementation doesn't seem to set the graphic offset of subwindows correctly when they overlap in certain ways. + // Use a separate controls window in this case. + // GLUI window at right containing manipulation controls and other buttons + int x = glutGet(GLUT_WINDOW_X) + glutGet(GLUT_WINDOW_WIDTH) + 4; + int y = glutGet(GLUT_WINDOW_Y); + GLUI* right_glui_window = GLUI_Master.create_glui( "", 0, x, y ); +#else + GLUI* right_glui_window = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_RIGHT ); +#endif + mViewRotationCtrl = right_glui_window->add_rotation( "Rotation", mViewRotation ); + mViewTranslationCtrl = right_glui_window->add_translation( "Translate", GLUI_TRANSLATION_XY, mViewPos ); + mViewTranslationCtrl->set_speed( 0.01f ); + mViewScaleCtrl = right_glui_window->add_translation( "Scale", GLUI_TRANSLATION_Z, &mViewPos[ 2 ] ); + mViewScaleCtrl->set_speed( 0.05f ); + right_glui_window->set_main_gfx_window( mAppWindow ); + + // right side window - app controls + mIdControlAddPanel = start_id++; + right_glui_window->add_statictext( "" ); + right_glui_window->add_separator(); + right_glui_window->add_statictext( "" ); + right_glui_window->add_button( "Add panel", mIdControlAddPanel, gluiCallbackWrapper ); + right_glui_window->add_statictext( "" ); + mIdControlRemPanel = start_id++; + right_glui_window->add_button( "Rem panel", mIdControlRemPanel, gluiCallbackWrapper ); + right_glui_window->add_statictext( "" ); + right_glui_window->add_separator(); + right_glui_window->add_statictext( "" ); + mIdControlCrashPlugin = start_id++; + right_glui_window->add_button( "Crash plugin", mIdControlCrashPlugin, gluiCallbackWrapper ); + mIdControlHangPlugin = start_id++; + right_glui_window->add_button( "Hang plugin", mIdControlHangPlugin, gluiCallbackWrapper ); + + right_glui_window->add_statictext( "" ); + right_glui_window->add_separator(); + right_glui_window->add_statictext( "" ); + mIdControlExitApp = start_id++; + right_glui_window->add_button( "Exit app", mIdControlExitApp, gluiCallbackWrapper ); + + //// top window - holds bookmark UI + mIdBookmarks = start_id++; + mSelBookmark = 0; + GLUI* glui_window_top = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP ); + mBookmarkList = glui_window_top->add_listbox( "", &mSelBookmark, mIdBookmarks, gluiCallbackWrapper ); + // only add the first 50 bookmarks - list can be very long sometimes (30,000+) + // when testing list of media URLs from AGNI for example + for( unsigned int each = 0; each < mBookmarks.size() && each < 50; ++each ) + mBookmarkList->add_item( each, const_cast< char* >( mBookmarks[ each ].first.c_str() ) ); + glui_window_top->set_main_gfx_window( mAppWindow ); + + glui_window_top->add_column( false ); + mIdUrlEdit = start_id++; + mUrlEdit = glui_window_top->add_edittext( "Url:", GLUI_EDITTEXT_TEXT, 0, mIdUrlEdit, gluiCallbackWrapper ); + mUrlEdit->set_w( 600 ); + GLUI* glui_window_top2 = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP ); + mIdUrlInitHistoryEdit = start_id++; + mUrlInitHistoryEdit = glui_window_top2->add_edittext( "Init History (separate by commas or semicolons):", + GLUI_EDITTEXT_TEXT, 0, mIdUrlInitHistoryEdit, gluiCallbackWrapper ); + mUrlInitHistoryEdit->set_w( 800 ); + + // top window - media controls for "time" media types (e.g. movies) + mGluiMediaTimeControlWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP ); + mGluiMediaTimeControlWindow->set_main_gfx_window( mAppWindow ); + mIdMediaTimeControlPlay = start_id++; + mGluiMediaTimeControlWindow->add_button( "PLAY", mIdMediaTimeControlPlay, gluiCallbackWrapper ); + mGluiMediaTimeControlWindow->add_column( false ); + mIdMediaTimeControlLoop = start_id++; + mGluiMediaTimeControlWindow->add_button( "LOOP", mIdMediaTimeControlLoop, gluiCallbackWrapper ); + mGluiMediaTimeControlWindow->add_column( false ); + mIdMediaTimeControlPause = start_id++; + mGluiMediaTimeControlWindow->add_button( "PAUSE", mIdMediaTimeControlPause, gluiCallbackWrapper ); + mGluiMediaTimeControlWindow->add_column( false ); + + GLUI_Button *button; + mIdMediaTimeControlRewind = start_id++; + button = mGluiMediaTimeControlWindow->add_button( "<<", mIdMediaTimeControlRewind, gluiCallbackWrapper ); + button->set_w(30); + mGluiMediaTimeControlWindow->add_column( false ); + mIdMediaTimeControlFastForward = start_id++; + button = mGluiMediaTimeControlWindow->add_button( ">>", mIdMediaTimeControlFastForward, gluiCallbackWrapper ); + button->set_w(30); + + mGluiMediaTimeControlWindow->add_column( true ); + + mIdMediaTimeControlStop = start_id++; + mGluiMediaTimeControlWindow->add_button( "STOP", mIdMediaTimeControlStop, gluiCallbackWrapper ); + mGluiMediaTimeControlWindow->add_column( false ); + mIdMediaTimeControlVolume = start_id++; + GLUI_Spinner* spinner = mGluiMediaTimeControlWindow->add_spinner( "Volume", 2, &mMediaTimeControlVolume, mIdMediaTimeControlVolume, gluiCallbackWrapper); + spinner->set_float_limits( 0, 100 ); + mGluiMediaTimeControlWindow->add_column( true ); + mIdMediaTimeControlSeekSeconds = start_id++; + spinner = mGluiMediaTimeControlWindow->add_spinner( "", 2, &mMediaTimeControlSeekSeconds, mIdMediaTimeControlSeekSeconds, gluiCallbackWrapper); + spinner->set_float_limits( 0, 200 ); + spinner->set_w( 32 ); + spinner->set_speed( 0.025f ); + mGluiMediaTimeControlWindow->add_column( false ); + mIdMediaTimeControlSeek = start_id++; + mGluiMediaTimeControlWindow->add_button( "SEEK", mIdMediaTimeControlSeek, gluiCallbackWrapper ); + mGluiMediaTimeControlWindow->add_column( false ); + + + // top window - media controls for "browser" media types (e.g. web browser) + mGluiMediaBrowserControlWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP ); + mGluiMediaBrowserControlWindow->set_main_gfx_window( mAppWindow ); + mIdMediaBrowserControlBack = start_id++; + mMediaBrowserControlBackButton = mGluiMediaBrowserControlWindow->add_button( "BACK", mIdMediaBrowserControlBack, gluiCallbackWrapper ); + mGluiMediaBrowserControlWindow->add_column( false ); + mIdMediaBrowserControlStop = start_id++; + mGluiMediaBrowserControlWindow->add_button( "STOP", mIdMediaBrowserControlStop, gluiCallbackWrapper ); + mGluiMediaBrowserControlWindow->add_column( false ); + mIdMediaBrowserControlForward = start_id++; + mMediaBrowserControlForwardButton = mGluiMediaBrowserControlWindow->add_button( "FORWARD", mIdMediaBrowserControlForward, gluiCallbackWrapper ); + mGluiMediaBrowserControlWindow->add_column( false ); + mIdMediaBrowserControlHome = start_id++; + mGluiMediaBrowserControlWindow->add_button( "HOME", mIdMediaBrowserControlHome, gluiCallbackWrapper ); + mGluiMediaBrowserControlWindow->add_column( false ); + mIdMediaBrowserControlReload = start_id++; + mGluiMediaBrowserControlWindow->add_button( "RELOAD", mIdMediaBrowserControlReload, gluiCallbackWrapper ); + mGluiMediaBrowserControlWindow->add_column( false ); + mIdMediaBrowserControlClearCache = start_id++; + mGluiMediaBrowserControlWindow->add_button( "CLEAR CACHE", mIdMediaBrowserControlClearCache, gluiCallbackWrapper ); + mGluiMediaBrowserControlWindow->add_column( false ); + mIdMediaBrowserControlClearCookies = start_id++; + mGluiMediaBrowserControlWindow->add_button( "CLEAR COOKIES", mIdMediaBrowserControlClearCookies, gluiCallbackWrapper ); + mGluiMediaBrowserControlWindow->add_column( false ); + mIdMediaBrowserControlEnableCookies = start_id++; + mMediaBrowserControlEnableCookies = 0; + mGluiMediaBrowserControlWindow->add_checkbox( "Enable Cookies", &mMediaBrowserControlEnableCookies, mIdMediaBrowserControlEnableCookies, gluiCallbackWrapper ); + + // top window - misc controls + GLUI* glui_window_misc_control = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP ); + mIdRandomPanelCount = start_id++; + mRandomPanelCount = 0; + glui_window_misc_control->add_checkbox( "Randomize panel count", &mRandomPanelCount, mIdRandomPanelCount, gluiCallbackWrapper ); + glui_window_misc_control->set_main_gfx_window( mAppWindow ); + glui_window_misc_control->add_column( true ); + mIdRandomBookmarks = start_id++; + mRandomBookmarks = 0; + glui_window_misc_control->add_checkbox( "Randomize bookmarks", &mRandomBookmarks, mIdRandomBookmarks, gluiCallbackWrapper ); + glui_window_misc_control->set_main_gfx_window( mAppWindow ); + glui_window_misc_control->add_column( true ); + + mIdDisableTimeout = start_id++; + mDisableTimeout = 0; + glui_window_misc_control->add_checkbox( "Disable plugin timeout", &mDisableTimeout, mIdDisableTimeout, gluiCallbackWrapper ); + glui_window_misc_control->set_main_gfx_window( mAppWindow ); + + // bottom window - status + mBottomGLUIWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_BOTTOM ); + mStatusText = mBottomGLUIWindow->add_statictext( "" ); + mBottomGLUIWindow->set_main_gfx_window( mAppWindow ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::resetView() +{ + mViewRotationCtrl->reset(); + + mViewScaleCtrl->set_x( 0.0f ); + mViewScaleCtrl->set_y( 0.0f ); + mViewScaleCtrl->set_z( 3.0f ); + + mViewTranslationCtrl->set_x( 0.0f ); + mViewTranslationCtrl->set_y( 0.0f ); + mViewTranslationCtrl->set_z( 0.0f ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::makePickTexture( int id, GLuint* texture_handle, unsigned char** texture_pixels ) +{ + int pick_texture_width = 1024; + int pick_texture_height = 1024; + int pick_texture_depth = 3; + unsigned char* ptr = new unsigned char[ pick_texture_width * pick_texture_height * pick_texture_depth ]; + for( int y = 0; y < pick_texture_height; ++y ) + { + for( int x = 0; x < pick_texture_width * pick_texture_depth ; x += pick_texture_depth ) + { + unsigned long bits = 0L; + bits |= ( id << 20 ) | ( y << 10 ) | ( x / 3 ); + unsigned char r_component = ( bits >> 16 ) & 0xff; + unsigned char g_component = ( bits >> 8 ) & 0xff; + unsigned char b_component = bits & 0xff; + + ptr[ y * pick_texture_width * pick_texture_depth + x + 0 ] = r_component; + ptr[ y * pick_texture_width * pick_texture_depth + x + 1 ] = g_component; + ptr[ y * pick_texture_width * pick_texture_depth + x + 2 ] = b_component; + }; + }; + + glGenTextures( 1, texture_handle ); + + checkGLError("glGenTextures"); + std::cout << "glGenTextures returned " << *texture_handle << std::endl; + + bindTexture( *texture_handle ); + glTexImage2D( GL_TEXTURE_2D, 0, + GL_RGB, + pick_texture_width, pick_texture_height, + 0, GL_RGB, GL_UNSIGNED_BYTE, ptr ); + + *texture_pixels = ptr; +} + +//////////////////////////////////////////////////////////////////////////////// +// +std::string LLMediaPluginTest::mimeTypeFromUrl( std::string& url ) +{ + // default to web + std::string mime_type = "text/html"; + + // we may need a more advanced MIME type accessor later :-) + if ( url.find( ".mov" ) != std::string::npos ) // Movies + mime_type = "video/quicktime"; + else + if ( url.find( ".txt" ) != std::string::npos ) // Apple Text descriptors + mime_type = "video/quicktime"; + else + if ( url.find( ".mp3" ) != std::string::npos ) // Apple Text descriptors + mime_type = "video/quicktime"; + else + if ( url.find( "example://" ) != std::string::npos ) // Example plugin + mime_type = "example/example"; + + return mime_type; +} + +//////////////////////////////////////////////////////////////////////////////// +// +std::string LLMediaPluginTest::pluginNameFromMimeType( std::string& mime_type ) +{ +#if LL_DARWIN + std::string plugin_name( "media_plugin_null.dylib" ); + if ( mime_type == "video/quicktime" ) + plugin_name = "media_plugin_quicktime.dylib"; + else + if ( mime_type == "text/html" ) + plugin_name = "media_plugin_webkit.dylib"; + +#elif LL_WINDOWS + std::string plugin_name( "media_plugin_null.dll" ); + + if ( mime_type == "video/quicktime" ) + plugin_name = "media_plugin_quicktime.dll"; + else + if ( mime_type == "text/html" ) + plugin_name = "media_plugin_webkit.dll"; + else + if ( mime_type == "example/example" ) + plugin_name = "media_plugin_example.dll"; + +#elif LL_LINUX + std::string plugin_name( "libmedia_plugin_null.so" ); + + if ( mime_type == "video/quicktime" ) + plugin_name = "libmedia_plugin_quicktime.so"; + else + if ( mime_type == "text/html" ) + plugin_name = "libmedia_plugin_webkit.so"; +#endif + return plugin_name; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::addMediaPanel( std::string url ) +{ + // Get the plugin filename using the URL + std::string mime_type = mimeTypeFromUrl( url ); + std::string plugin_name = pluginNameFromMimeType( mime_type ); + + // create a random size for the new media + int media_width; + int media_height; + getRandomMediaSize( media_width, media_height, mime_type ); + + // make a new plugin + LLPluginClassMedia* media_source = new LLPluginClassMedia(this); + + // tell the plugin what size we asked for + media_source->setSize( media_width, media_height ); + + // Use the launcher start and initialize the plugin +#if LL_DARWIN || LL_LINUX + std::string launcher_name( "SLPlugin" ); +#elif LL_WINDOWS + std::string launcher_name( "SLPlugin.exe" ); +#endif + + // for this test app, use the cwd as the user data path (ugh). +#if LL_WINDOWS + std::string user_data_path = ".\\"; +#else + char cwd[ FILENAME_MAX ]; + if (NULL == getcwd( cwd, FILENAME_MAX - 1 )) + { + std::cerr << "Couldn't get cwd - probably too long - failing to init." << std::endl; + return; + } + std::string user_data_path = std::string( cwd ) + "/"; +#endif + media_source->setUserDataPath(user_data_path); + media_source->init( launcher_name, plugin_name, false ); + media_source->setDisableTimeout(mDisableTimeout); + + // make a new panel and save parameters + mediaPanel* panel = new mediaPanel; + panel->mMediaSource = media_source; + panel->mStartUrl = url; + panel->mMimeType = mime_type; + panel->mMediaWidth = media_width; + panel->mMediaHeight = media_height; + panel->mTextureWidth = 0; + panel->mTextureHeight = 0; + panel->mTextureScaleX = 0; + panel->mTextureScaleY = 0; + panel->mMediaTextureHandle = 0; + panel->mPickTextureHandle = 0; + panel->mAppTextureCoordsOpenGL = false; // really need an 'undefined' state here too + panel->mReadyToRender = false; + + // look through current media panels to find an unused index number + bool id_exists = true; + for( int nid = 0; nid < mMaxPanels; ++nid ) + { + // does this id exist already? + id_exists = false; + for( int pid = 0; pid < (int)mMediaPanels.size(); ++pid ) + { + if ( nid == mMediaPanels[ pid ]->mId ) + { + id_exists = true; + break; + }; + }; + + // id wasn't found so we can use it + if ( ! id_exists ) + { + panel->mId = nid; + break; + }; + }; + + // if we get here and this flag is set, there is no room for any more panels + if ( id_exists ) + { + std::cout << "No room for any more panels" << std::endl; + } + else + { + // now we have the ID we can use it to make the + // pick texture (id is baked into texture pixels) + makePickTexture( panel->mId, &panel->mPickTextureHandle, &panel->mPickTexturePixels ); + + // save this in the list of panels + mMediaPanels.push_back( panel ); + + // select the panel that was just created + selectPanel( panel ); + + // load and start the URL + panel->mMediaSource->loadURI( url ); + panel->mMediaSource->start(); + + std::cout << "Adding new media panel for " << url << "(" << media_width << "x" << media_height << ") with index " << panel->mId << " - total panels = " << mMediaPanels.size() << std::endl; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::updateMediaPanel( mediaPanel* panel ) +{ +// checkGLError("LLMediaPluginTest::updateMediaPanel"); + + if ( ! panel ) + return; + + if(!panel->mMediaSource || !panel->mMediaSource->textureValid()) + { + panel->mReadyToRender = false; + return; + } + + // take a reference copy of the plugin values since they + // might change during this lifetime of this function + int plugin_media_width = panel->mMediaSource->getWidth(); + int plugin_media_height = panel->mMediaSource->getHeight(); + int plugin_texture_width = panel->mMediaSource->getBitsWidth(); + int plugin_texture_height = panel->mMediaSource->getBitsHeight(); + + // If the texture isn't created or the media or texture dimensions changed AND + // the sizes are valid then we need to delete the old media texture (if necessary) + // then make a new one. + if ((panel->mMediaTextureHandle == 0 || + panel->mMediaWidth != plugin_media_width || + panel->mMediaHeight != plugin_media_height || + panel->mTextureWidth != plugin_texture_width || + panel->mTextureHeight != plugin_texture_height) && + ( plugin_media_width > 0 && plugin_media_height > 0 && + plugin_texture_width > 0 && plugin_texture_height > 0 ) ) + { + std::cout << "Valid media size (" << plugin_media_width << " x " << plugin_media_height + << ") and texture size (" << plugin_texture_width << " x " << plugin_texture_height + << ") for panel with ID=" << panel->mId << " - making texture" << std::endl; + + // delete old GL texture + if ( isTexture( panel->mMediaTextureHandle ) ) + { + std::cerr << "updateMediaPanel: deleting texture " << panel->mMediaTextureHandle << std::endl; + glDeleteTextures( 1, &panel->mMediaTextureHandle ); + panel->mMediaTextureHandle = 0; + } + + std::cerr << "before: pick texture is " << panel->mPickTextureHandle << ", media texture is " << panel->mMediaTextureHandle << std::endl; + + // make a GL texture based on the dimensions the plugin told us + GLuint new_texture = 0; + glGenTextures( 1, &new_texture ); + + checkGLError("glGenTextures"); + + std::cout << "glGenTextures returned " << new_texture << std::endl; + + panel->mMediaTextureHandle = new_texture; + + bindTexture( panel->mMediaTextureHandle ); + + std::cout << "Setting texture size to " << plugin_texture_width << " x " << plugin_texture_height << std::endl; + glTexImage2D( GL_TEXTURE_2D, 0, + GL_RGB, + plugin_texture_width, plugin_texture_height, + 0, GL_RGB, GL_UNSIGNED_BYTE, + 0 ); + + + std::cerr << "after: pick texture is " << panel->mPickTextureHandle << ", media texture is " << panel->mMediaTextureHandle << std::endl; + }; + + // update our record of the media and texture dimensions + // NOTE: do this after we we check for sizes changes + panel->mMediaWidth = plugin_media_width; + panel->mMediaHeight = plugin_media_height; + panel->mTextureWidth = plugin_texture_width; + panel->mTextureHeight = plugin_texture_height; + if ( plugin_texture_width > 0 ) + { + panel->mTextureScaleX = (double)panel->mMediaWidth / (double)panel->mTextureWidth; + }; + if ( plugin_texture_height > 0 ) + { + panel->mTextureScaleY = (double)panel->mMediaHeight / (double)panel->mTextureHeight; + }; + + // update the flag which tells us if the media source uses OprnGL coords or not. + panel->mAppTextureCoordsOpenGL = panel->mMediaSource->getTextureCoordsOpenGL(); + + // Check to see if we have enough to render this panel. + // If we do, set a flag that the display functions use so + // they only render a panel with media if it's ready. + if ( panel->mMediaWidth < 0 || + panel->mMediaHeight < 0 || + panel->mTextureWidth < 1 || + panel->mTextureHeight < 1 || + panel->mMediaTextureHandle == 0 ) + { + panel->mReadyToRender = false; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::replaceMediaPanel( mediaPanel* panel, std::string url ) +{ + // no media panels so we can't change anything - have to add + if ( mMediaPanels.size() == 0 ) + return; + + // sanity check + if ( ! panel ) + return; + + int index; + for(index = 0; index < (int)mMediaPanels.size(); index++) + { + if(mMediaPanels[index] == panel) + break; + } + + if(index >= (int)mMediaPanels.size()) + { + // panel isn't in mMediaPanels + return; + } + + std::cout << "Replacing media panel with index " << panel->mId << std::endl; + + int panel_id = panel->mId; + + if(mSelectedPanel == panel) + mSelectedPanel = NULL; + + delete panel; + + // Get the plugin filename using the URL + std::string mime_type = mimeTypeFromUrl( url ); + std::string plugin_name = pluginNameFromMimeType( mime_type ); + + // create a random size for the new media + int media_width; + int media_height; + getRandomMediaSize( media_width, media_height, mime_type ); + + // make a new plugin + LLPluginClassMedia* media_source = new LLPluginClassMedia(this); + + // tell the plugin what size we asked for + media_source->setSize( media_width, media_height ); + + // Use the launcher start and initialize the plugin +#if LL_DARWIN || LL_LINUX + std::string launcher_name( "SLPlugin" ); +#elif LL_WINDOWS + std::string launcher_name( "SLPlugin.exe" ); +#endif + + // for this test app, use the cwd as the user data path (ugh). +#if LL_WINDOWS + std::string user_data_path = ".\\"; +#else + char cwd[ FILENAME_MAX ]; + if (NULL == getcwd( cwd, FILENAME_MAX - 1 )) + { + std::cerr << "Couldn't get cwd - probably too long - failing to init." << std::endl; + return; + } + std::string user_data_path = std::string( cwd ) + "/"; +#endif + + media_source->setUserDataPath(user_data_path); + media_source->init( launcher_name, plugin_name, false ); + media_source->setDisableTimeout(mDisableTimeout); + + // make a new panel and save parameters + panel = new mediaPanel; + panel->mMediaSource = media_source; + panel->mStartUrl = url; + panel->mMimeType = mime_type; + panel->mMediaWidth = media_width; + panel->mMediaHeight = media_height; + panel->mTextureWidth = 0; + panel->mTextureHeight = 0; + panel->mTextureScaleX = 0; + panel->mTextureScaleY = 0; + panel->mMediaTextureHandle = 0; + panel->mPickTextureHandle = 0; + panel->mAppTextureCoordsOpenGL = false; // really need an 'undefined' state here too + panel->mReadyToRender = false; + + panel->mId = panel_id; + + // Replace the entry in the panels array + mMediaPanels[index] = panel; + + // now we have the ID we can use it to make the + // pick texture (id is baked into texture pixels) + makePickTexture( panel->mId, &panel->mPickTextureHandle, &panel->mPickTexturePixels ); + + // select the panel that was just created + selectPanel( panel ); + + // load and start the URL + panel->mMediaSource->loadURI( url ); + panel->mMediaSource->start(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::getRandomMediaSize( int& width, int& height, std::string mime_type ) +{ + // Make a new media source with a random size which we'll either + // directly or the media plugin will tell us what it wants later. + // Use a random size so we can test support for weird media sizes. + // (Almost everything else will get filled in later once the + // plugin responds) + // NB. Do we need to enforce that width is on 4 pixel boundary? + width = ( ( rand() % 170 ) + 30 ) * 4; + height = ( ( rand() % 170 ) + 30 ) * 4; + + // adjust this random size if it's a browser so we get + // a more useful size for testing.. + if ( mime_type == "text/html" || mime_type == "example/example" ) + { + width = ( ( rand() % 100 ) + 100 ) * 4; + height = ( width * ( ( rand() % 400 ) + 1000 ) ) / 1000; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::remMediaPanel( mediaPanel* panel ) +{ + // always leave one panel + if ( mMediaPanels.size() == 1 ) + return; + + // sanity check - don't think this can happen but see above for a case where it might... + if ( ! panel ) + return; + + std::cout << "Removing media panel with index " << panel->mId << " - total panels = " << mMediaPanels.size() - 1 << std::endl; + + if(mSelectedPanel == panel) + mSelectedPanel = NULL; + + delete panel; + + // remove from storage list + for( int i = 0; i < (int)mMediaPanels.size(); ++i ) + { + if ( mMediaPanels[ i ] == panel ) + { + mMediaPanels.erase( mMediaPanels.begin() + i ); + break; + }; + }; + + // select the first panel + selectPanel( mMediaPanels[ 0 ] ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::updateStatusBar() +{ + if ( ! mSelectedPanel ) + return; + + // cache results - this is a very slow function + static int cached_id = -1; + static int cached_media_width = -1; + static int cached_media_height = -1; + static int cached_texture_width = -1; + static int cached_texture_height = -1; + static bool cached_supports_browser_media = true; + static bool cached_supports_time_media = false; + static int cached_movie_time = -1; + + static std::string cached_plugin_version = ""; + if ( + cached_id == mSelectedPanel->mId && + cached_media_width == mSelectedPanel->mMediaWidth && + cached_media_height == mSelectedPanel->mMediaHeight && + cached_texture_width == mSelectedPanel->mTextureWidth && + cached_texture_height == mSelectedPanel->mTextureHeight && + cached_supports_browser_media == mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() && + cached_supports_time_media == mSelectedPanel->mMediaSource->pluginSupportsMediaTime() && + cached_plugin_version == mSelectedPanel->mMediaSource->getPluginVersion() && + cached_movie_time == (int)mSelectedPanel->mMediaSource->getCurrentTime() + ) + { + // nothing changed so don't spend time in this shitty function + return; + }; + + std::ostringstream stream( "" ); + + stream.str( "" ); + stream.clear(); + + stream << "Id: "; + stream << std::setw( 2 ) << std::setfill( '0' ); + stream << mSelectedPanel->mId; + stream << " | "; + stream << "Media: "; + stream << std::setw( 3 ) << std::setfill( '0' ); + stream << mSelectedPanel->mMediaWidth; + stream << " x "; + stream << std::setw( 3 ) << std::setfill( '0' ); + stream << mSelectedPanel->mMediaHeight; + stream << " | "; + stream << "Texture: "; + stream << std::setw( 4 ) << std::setfill( '0' ); + stream << mSelectedPanel->mTextureWidth; + stream << " x "; + stream << std::setw( 4 ) << std::setfill( '0' ); + stream << mSelectedPanel->mTextureHeight; + stream << " | "; + if ( mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() ) + stream << "BROWSER"; + else + if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() ) + stream << "TIME "; + stream << " | "; + stream << mSelectedPanel->mMediaSource->getPluginVersion(); + stream << " | "; + if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() ) + { + stream << std::setw( 3 ) << std::setfill( '0' ); + stream << (int)mSelectedPanel->mMediaSource->getCurrentTime(); + stream << " / "; + stream << std::setw( 3 ) << std::setfill( '0' ); + stream << (int)mSelectedPanel->mMediaSource->getDuration(); + stream << " @ "; + stream << (int)mSelectedPanel->mMediaSource->getCurrentPlayRate(); + stream << " | "; + }; + + glutSetWindow( mBottomGLUIWindow->get_glut_window_id() ); + mStatusText->set_text( const_cast< char*>( stream.str().c_str() ) ); + glutSetWindow( mAppWindow ); + + // caching + cached_id = mSelectedPanel->mId; + cached_media_width = mSelectedPanel->mMediaWidth; + cached_media_height = mSelectedPanel->mMediaHeight; + cached_texture_width = mSelectedPanel->mTextureWidth; + cached_texture_height = mSelectedPanel->mTextureHeight; + cached_supports_browser_media = mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser(); + cached_supports_time_media = mSelectedPanel->mMediaSource->pluginSupportsMediaTime(); + cached_plugin_version = mSelectedPanel->mMediaSource->getPluginVersion(); + cached_movie_time = (int)mSelectedPanel->mMediaSource->getCurrentTime(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::dumpPanelInfo() +{ + std::cout << std::endl << "===== Media Panels =====" << std::endl; + for( int i = 0; i < (int)mMediaPanels.size(); ++i ) + { + std::cout << std::setw( 2 ) << std::setfill( '0' ); + std::cout << i + 1 << "> "; + std::cout << "Id: "; + std::cout << std::setw( 2 ) << std::setfill( '0' ); + std::cout << mMediaPanels[ i ]->mId; + std::cout << " | "; + std::cout << "Media: "; + std::cout << std::setw( 3 ) << std::setfill( '0' ); + std::cout << mMediaPanels[ i ]->mMediaWidth; + std::cout << " x "; + std::cout << std::setw( 3 ) << std::setfill( '0' ); + std::cout << mMediaPanels[ i ]->mMediaHeight; + std::cout << " | "; + std::cout << "Texture: "; + std::cout << std::setw( 4 ) << std::setfill( '0' ); + std::cout << mMediaPanels[ i ]->mTextureWidth; + std::cout << " x "; + std::cout << std::setw( 4 ) << std::setfill( '0' ); + std::cout << mMediaPanels[ i ]->mTextureHeight; + std::cout << " | "; + if ( mMediaPanels[ i ] == mSelectedPanel ) + std::cout << "(selected)"; + + std::cout << std::endl; + }; + std::cout << "========================" << std::endl; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + // Uncomment this to make things much, much quieter. +// return; + + switch(event) + { + case MEDIA_EVENT_CONTENT_UPDATED: + // too spammy -- don't log these +// std::cerr << "Media event: MEDIA_EVENT_CONTENT_UPDATED " << std::endl; + break; + + case MEDIA_EVENT_TIME_DURATION_UPDATED: + // too spammy -- don't log these +// std::cerr << "Media event: MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << std::endl; + break; + + case MEDIA_EVENT_SIZE_CHANGED: + std::cerr << "Media event: MEDIA_EVENT_SIZE_CHANGED " << std::endl; + break; + + case MEDIA_EVENT_CURSOR_CHANGED: + std::cerr << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << std::endl; + break; + + case MEDIA_EVENT_NAVIGATE_BEGIN: + std::cerr << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN " << std::endl; + break; + + case MEDIA_EVENT_NAVIGATE_COMPLETE: + std::cerr << "Media event: MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << std::endl; + break; + + case MEDIA_EVENT_PROGRESS_UPDATED: + std::cerr << "Media event: MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << std::endl; + break; + + case MEDIA_EVENT_STATUS_TEXT_CHANGED: + std::cerr << "Media event: MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << std::endl; + break; + + case MEDIA_EVENT_NAME_CHANGED: + std::cerr << "Media event: MEDIA_EVENT_NAME_CHANGED, new name is: " << self->getMediaName() << std::endl; + glutSetWindowTitle( self->getMediaName().c_str() ); + break; + + case MEDIA_EVENT_LOCATION_CHANGED: + { + std::cerr << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << std::endl; + mediaPanel* panel = findMediaPanel(self); + if(panel != NULL) + { + panel->mStartUrl = self->getLocation(); + if(panel == mSelectedPanel) + { + mUrlEdit->set_text(const_cast<char*>(panel->mStartUrl.c_str()) ); + } + } + } + break; + + case MEDIA_EVENT_CLICK_LINK_HREF: + std::cerr << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, uri is " << self->getClickURL() << std::endl; + break; + + case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: + std::cerr << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << std::endl; + break; + + case MEDIA_EVENT_PLUGIN_FAILED: + std::cerr << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << std::endl; + break; + + case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: + std::cerr << "Media event: MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << std::endl; + break; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +static void gluiCallbackWrapper( int control_id ) +{ + if ( gApplication ) + gApplication->gluiCallback( control_id ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void glutReshape( int width, int height ) +{ + if ( gApplication ) + gApplication->reshape( width, height ); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutDisplay() +{ + if ( gApplication ) + gApplication->display(); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutIdle(int update_ms) +{ + GLUI_Master.set_glutTimerFunc( update_ms, glutIdle, update_ms); + + if ( gApplication ) + gApplication->idle(); + +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutKeyboard( unsigned char key, int x, int y ) +{ + if ( gApplication ) + gApplication->keyboard( key ); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutMousePassive( int x, int y ) +{ + if ( gApplication ) + gApplication->mousePassive( x, y ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void glutMouseMove( int x , int y ) +{ + if ( gApplication ) + gApplication->mouseMove( x, y ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void glutMouseButton( int button, int state, int x, int y ) +{ + if ( gApplication ) + gApplication->mouseButton( button, state, x, y ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +int main( int argc, char* argv[] ) +{ +#if LL_DARWIN + // Set the current working directory to <application bundle>/Contents/Resources/ + CFURLRef resources_url = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if(resources_url != NULL) + { + CFStringRef resources_string = CFURLCopyFileSystemPath(resources_url, kCFURLPOSIXPathStyle); + CFRelease(resources_url); + if(resources_string != NULL) + { + char buffer[PATH_MAX] = ""; + if(CFStringGetCString(resources_string, buffer, sizeof(buffer), kCFStringEncodingUTF8)) + { + chdir(buffer); + } + CFRelease(resources_string); + } + } +#endif + + glutInit( &argc, argv ); + glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB ); + + const int app_window_x = 80; + const int app_window_y = 0; + const int app_window_width = 960; + const int app_window_height = 960; + + glutInitWindowPosition( app_window_x, app_window_y ); + glutInitWindowSize( app_window_width, app_window_height ); + + int app_window_handle = glutCreateWindow( "LLMediaPluginTest" ); + + glutDisplayFunc( glutDisplay ); + + GLUI_Master.set_glutReshapeFunc( glutReshape ); + GLUI_Master.set_glutKeyboardFunc( glutKeyboard ); + GLUI_Master.set_glutMouseFunc( glutMouseButton ); + + glutPassiveMotionFunc( glutMousePassive ); + glutMotionFunc( glutMouseMove ); + + glutSetWindow( app_window_handle ); + + gApplication = new LLMediaPluginTest( app_window_handle, app_window_width, app_window_height ); + + // update at approximately 60hz + int update_ms = 1000 / 60; + + GLUI_Master.set_glutTimerFunc( update_ms, glutIdle, update_ms); + + glutMainLoop(); + + delete gApplication; +} diff --git a/linden/indra/test_apps/llplugintest/llmediaplugintest.h b/linden/indra/test_apps/llplugintest/llmediaplugintest.h new file mode 100644 index 000000000..c2b2baba9 --- /dev/null +++ b/linden/indra/test_apps/llplugintest/llmediaplugintest.h @@ -0,0 +1,201 @@ +/** + * @file LLMediaPluginTest.cpp + * @brief Primary test application for LLMedia (Separate Process) Plugin system + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_MEDIA_PLUGIN_TEST_H +#define LL_MEDIA_PLUGIN_TEST_H + +#include <vector> +#include <string> +#include "llpluginclassmedia.h" +#include "llgl.h" + +// Forward declarations +class GLUI_Rotation; +class GLUI_Translation; +class GLUI_Listbox; +class GLUI_EditText; +class GLUI_StaticText; +class GLUI; +class GLUI_Button; + +//////////////////////////////////////////////////////////////////////////////// +// +struct mediaPanel +{ + public: + mediaPanel(); + ~mediaPanel(); + int mId; + std::string mStartUrl; + std::string mMimeType; + LLPluginClassMedia *mMediaSource; + int mMediaWidth; + int mMediaHeight; + int mTextureWidth; + int mTextureHeight; + double mTextureScaleX; + double mTextureScaleY; + GLuint mMediaTextureHandle; + GLuint mPickTextureHandle; + unsigned char* mPickTexturePixels; + bool mAppTextureCoordsOpenGL; + bool mReadyToRender; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +class LLMediaPluginTest : public LLPluginClassMediaOwner +{ + public: + LLMediaPluginTest( int app_window, int window_width, int window_height ); + ~LLMediaPluginTest(); + + void reshape( int width, int height ); + void display(); + void idle(); + void gluiCallback( int control_id ); + void keyboard( int key ); + void mousePassive( int x, int y ); + void mouseButton( int button, int state, int x, int y ); + void mouseMove( int x, int y ); + + void bindTexture(GLuint texture, GLint row_length = 0, GLint alignment = 1); + bool checkGLError(const char *name = "OpenGL"); + void drawGeometry( int panel ); + void startPanelHighlight( float red, float green, float blue, float line_width ); + void endPanelHighlight(); + enum { DrawTypePickTexture, DrawTypeMediaTexture }; + void draw( int draw_type ); + void windowPosToTexturePos( int window_x, int window_y, int& media_x, int& media_y, int& id ); + + void addMediaPanel( std::string url ); + void updateMediaPanel( mediaPanel* panel ); + void remMediaPanel( mediaPanel* panel ); + void replaceMediaPanel( mediaPanel* panel, std::string url ); + void getRandomMediaSize( int& width, int& height, std::string mime_type ); + void navigateToNewURI( std::string uri ); + void initUrlHistory( std::string uri ); + void selectPanelById( int id ); + void selectPanel( mediaPanel* panel ); + mediaPanel* findMediaPanel( LLPluginClassMedia* panel ); + void makePickTexture( int id, GLuint* texture_handle, unsigned char** texture_pixels ); + void makeChrome(); + void resetView(); + + void dumpPanelInfo(); + void updateStatusBar(); + + // Inherited from LLPluginClassMediaOwner + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent); + + private: + const int mVersionMajor; + const int mVersionMinor; + const int mVersionPatch; + const int mMaxPanels; + int mAppWindow; + int mWindowWidth; + int mWindowHeight; + int mCurMouseX; + int mCurMouseY; + unsigned char mPixelReadColor[ 3 ]; + bool mFuzzyMedia; + const std::string mHomeWebUrl; + + std::vector< mediaPanel* > mMediaPanels; + mediaPanel* mSelectedPanel; + std::string mimeTypeFromUrl( std::string& url ); + std::string pluginNameFromMimeType( std::string& mime_type ); + + GLUI_Rotation* mViewRotationCtrl; + GLUI_Translation* mViewScaleCtrl; + GLUI_Translation* mViewTranslationCtrl; + float mViewportAspect; + float mViewPos[ 3 ]; + float mViewRotation[ 16 ]; + + int mIdControlAddPanel; + int mIdControlRemPanel; + + std::vector< std::pair< std::string, std::string > > mBookmarks; + GLUI_Listbox* mBookmarkList; + int mIdBookmarks; + int mIdUrlEdit; + GLUI_EditText* mUrlEdit; + int mIdUrlInitHistoryEdit; + GLUI_EditText* mUrlInitHistoryEdit; + int mSelBookmark; + int mIdRandomPanelCount; + int mRandomPanelCount; + int mIdRandomBookmarks; + int mRandomBookmarks; + int mIdDisableTimeout; + int mDisableTimeout; + int mIdControlCrashPlugin; + int mIdControlHangPlugin; + int mIdControlExitApp; + + GLUI* mGluiMediaTimeControlWindow; + int mIdMediaTimeControlPlay; + int mIdMediaTimeControlLoop; + int mIdMediaTimeControlPause; + int mIdMediaTimeControlStop; + int mIdMediaTimeControlSeek; + int mIdMediaTimeControlVolume; + int mMediaTimeControlVolume; + int mIdMediaTimeControlSeekSeconds; + int mMediaTimeControlSeekSeconds; + int mIdMediaTimeControlRewind; + int mIdMediaTimeControlFastForward; + + GLUI* mGluiMediaBrowserControlWindow; + int mIdMediaBrowserControlBack; + GLUI_Button* mMediaBrowserControlBackButton; + int mIdMediaBrowserControlStop; + int mIdMediaBrowserControlForward; + GLUI_Button* mMediaBrowserControlForwardButton; + bool mGluiMediaTimeControlWindowFlag; + bool mGluiMediaBrowserControlWindowFlag; + bool mMediaBrowserControlBackButtonFlag; + bool mMediaBrowserControlForwardButtonFlag; + int mIdMediaBrowserControlHome; + int mIdMediaBrowserControlReload; + int mIdMediaBrowserControlClearCache; + int mIdMediaBrowserControlClearCookies; + int mIdMediaBrowserControlEnableCookies; + int mMediaBrowserControlEnableCookies; + + GLUI* mBottomGLUIWindow; + GLUI_StaticText* mStatusText; +}; + +#endif // LL_MEDIA_PLUGIN_TEST_H + diff --git a/linden/indra/test_apps/llplugintest/media_mappings.txt b/linden/indra/test_apps/llplugintest/media_mappings.txt new file mode 100644 index 000000000..74188bc95 --- /dev/null +++ b/linden/indra/test_apps/llplugintest/media_mappings.txt @@ -0,0 +1,3 @@ +Flash demo_media_plugin_flash.dll +ColNoise demo_media_plugin.dll +CheckBounce demo_media_plugin_2.dll diff --git a/linden/indra/test_apps/llplugintest/media_plugin_test.cpp b/linden/indra/test_apps/llplugintest/media_plugin_test.cpp new file mode 100644 index 000000000..8e42fa7ea --- /dev/null +++ b/linden/indra/test_apps/llplugintest/media_plugin_test.cpp @@ -0,0 +1,511 @@ +/** + * @file demo_plugin.cpp + * @brief Test plugin to be loaded by the llplugin testbed. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "indra_constants.h" + +#include "lltimer.h" // for ms_sleep() +#include "llpumpio.h" +#include "llapr.h" +#include "llerrorcontrol.h" +#include "llpluginclassmedia.h" + +#include <string> +#include <iostream> +#include <stdlib.h> +#include <time.h> + +#include "llmediaplugintest.h" // for GLUT headers + + +//////////////////////////////////////////////////////////////////////////////// +// +class mediaPluginTest : public LLPluginClassMediaOwner +{ + private: + int mAppWindowWidth; + int mAppWindowHeight; + LLPluginClassMedia* mMediaSource; + int mAppTextureWidth; + int mAppTextureHeight; + bool mAppTextureCoordsOpenGL; + GLuint mAppTexture; + std::string mAppWindowName; + std::string mHomeUrl; + std::string mLauncherFilename; + std::string mPluginFilename; + + LLPluginClassMedia *mPlugin; + + public: + mediaPluginTest(const std::string &launcher_filename, const std::string &plugin_filename) : + mAppWindowWidth( 800 ), + mAppWindowHeight( 600 ), + mAppTextureWidth( 0 ), + mAppTextureHeight( 0 ), + mAppTextureCoordsOpenGL(false), + mAppTexture( 0 ), + mAppWindowName( "Media Simple Test" ), + mHomeUrl( "" ) + { + mLauncherFilename = launcher_filename; + mMediaSource = new LLPluginClassMedia(this); + mMediaSource->init(launcher_filename, plugin_filename); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + virtual ~mediaPluginTest() + { + delete mMediaSource; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void createTexture() + { + // create the texture used to display the browser data + if(mMediaSource->textureValid()) + { + mAppTextureWidth = mMediaSource->getTextureWidth(); + mAppTextureHeight = mMediaSource->getTextureHeight(); + mAppTextureCoordsOpenGL = mMediaSource->getTextureCoordsOpenGL(); + + if(mAppTexture != 0) + { + glDeleteTextures( 1, &mAppTexture ); + mAppTexture = 0; + } + + glGenTextures( 1, &mAppTexture ); + glBindTexture( GL_TEXTURE_2D, mAppTexture ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexImage2D( GL_TEXTURE_2D, 0, + mMediaSource->getTextureFormatInternal(), + mAppTextureWidth, + mAppTextureHeight, + 0, + mMediaSource->getTextureFormatPrimary(), + mMediaSource->getTextureFormatType(), + NULL ); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // + void initGL() + { + // OpenGL initialization + glClearColor( 0.0f, 0.0f, 0.0f, 0.5f); + glEnable( GL_COLOR_MATERIAL ); + glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); + glEnable( GL_TEXTURE_2D ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glEnable( GL_CULL_FACE ); + } + + //////////////////////////////////////////////////////////////////////////////// + // + void reshape( int width, int height ) + { + if ( height == 0 ) + height = 1; + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + + glViewport( 0, 0, width, height ); + glOrtho( 0.0f, width, height, 0.0f, -1.0f, 1.0f ); + + // we use these values elsewhere so save + mAppWindowWidth = width; + mAppWindowHeight = height; + + // Request a media size change + mMediaSource->setSize(width, height); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + glutPostRedisplay(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void idle() + { + // lots of updates for smooth motion + glutPostRedisplay(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void display() + { + mMediaSource->idle(); + + // Check whether the texture needs to be recreated. + if(mMediaSource->textureValid()) + { + if( + (mAppTextureWidth != mMediaSource->getTextureWidth() || mAppTextureHeight != mMediaSource->getTextureHeight()) && + (mAppWindowWidth == mMediaSource->getWidth() && mAppWindowHeight == mMediaSource->getHeight()) + ) + { + // Attempt to (re)create the texture + createTexture(); + } + } + + // clear screen + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + glLoadIdentity(); + + if(mAppTexture != 0) + { + // use the browser texture + glBindTexture( GL_TEXTURE_2D, mAppTexture ); + + // If dirty, update the texture. + LLRect dirtyRect; + if(!mMediaSource->textureValid()) + { +// LL_DEBUGS("media_plugin_test") << "Resize in progress, skipping update..." << LL_ENDL; + } + else if(mAppWindowWidth != mMediaSource->getWidth() || mAppWindowHeight != mMediaSource->getHeight()) + { + // A resize is in progress. Just wait for it... + } + else if(mMediaSource->getDirty(&dirtyRect)) + { + // grab the page + const unsigned char* pixels = mMediaSource->getBitsData(); + if ( pixels ) + { + // write them into the texture + + // Paranoia: intersect dirtyRect with (0, 0, mAppTextureWidth, mAppTextureHeight)? + + int x_offset = dirtyRect.mLeft; + int y_offset = dirtyRect.mBottom; + int width = dirtyRect.mRight - dirtyRect.mLeft; + int height = dirtyRect.mTop - dirtyRect.mBottom; + + LL_DEBUGS("media_plugin_test") << "Updating, dirty rect is (" + << dirtyRect.mLeft << ", " + << dirtyRect.mTop << ", " + << dirtyRect.mRight << ", " + << dirtyRect.mBottom << "), update params are: (" + << x_offset << ", " + << y_offset << ", " + << width << ", " + << height << ")" + << LL_ENDL; + + // Offset the pixels pointer properly + pixels += (y_offset * mMediaSource->getTextureDepth() * mMediaSource->getTextureWidth()); + pixels += (x_offset * mMediaSource->getTextureDepth()); + + glPixelStorei(GL_UNPACK_ROW_LENGTH, mMediaSource->getTextureWidth()); + + glTexSubImage2D( GL_TEXTURE_2D, 0, + x_offset, + y_offset, + width, + height, + mMediaSource->getTextureFormatPrimary(), + mMediaSource->getTextureFormatType(), + pixels ); + + mMediaSource->resetDirty(); + } + } + + // scale the texture so that it fits the screen + GLdouble media_texture_x = mAppWindowWidth / (double)mAppTextureWidth; + GLdouble media_texture_y = mAppWindowHeight / (double)mAppTextureHeight; + + // draw the single quad full screen (orthographic) + + glEnable( GL_TEXTURE_2D ); + glColor3f( 1.0f, 1.0f, 1.0f ); + glBegin( GL_QUADS ); + if(mAppTextureCoordsOpenGL) + { + // Render the texture as per opengl coords (where 0,0 is at the lower left) + glTexCoord2d( 0, 0 ); + glVertex2d( 0, 0 ); + + glTexCoord2d( 0 , media_texture_y ); + glVertex2d( 0, mAppWindowHeight); + + glTexCoord2d( media_texture_x, media_texture_y ); + glVertex2d( mAppWindowWidth , mAppWindowHeight); + + glTexCoord2d( media_texture_x, 0 ); + glVertex2d( mAppWindowWidth, 0 ); + } + else + { + // Render the texture the "other way round" (where 0,0 is at the upper left) + glTexCoord2d( 0, media_texture_y ); + glVertex2d( 0, 0 ); + + glTexCoord2d( 0 , 0 ); + glVertex2d( 0, mAppWindowHeight); + + glTexCoord2d( media_texture_x, 0 ); + glVertex2d( mAppWindowWidth , mAppWindowHeight); + + glTexCoord2d( media_texture_x, media_texture_y ); + glVertex2d( mAppWindowWidth, 0 ); + } + glEnd(); + + } + + glutSwapBuffers(); + }; + + + //////////////////////////////////////////////////////////////////////////////// + // + MASK getModifiers(void) + { + MASK result = 0; + + int modifiers = glutGetModifiers(); + + if(modifiers & GLUT_ACTIVE_SHIFT) + result |= MASK_SHIFT; + if(modifiers & GLUT_ACTIVE_CTRL) + result |= MASK_CONTROL; + if(modifiers & GLUT_ACTIVE_ALT) + result |= MASK_ALT; + + return result; + } + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseButton( int button, int state, int x, int y ) + { + // Texture has been scaled so it's 1:1 with screen pixels, so no need to scale mouse coords here. +// x = ( x * mAppTextureWidth ) / mAppWindowWidth; +// y = ( y * mAppTextureHeight ) / mAppWindowHeight; + + if ( button == GLUT_LEFT_BUTTON ) + { + if ( state == GLUT_DOWN ) + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, x, y, getModifiers()); + else if ( state == GLUT_UP ) + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, x, y, getModifiers()); + } + + // force a GLUT update + glutPostRedisplay(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseMove( int x , int y ) + { + // Texture has been scaled so it's 1:1 with screen pixels, so no need to scale mouse coords here. +// x = ( x * mAppTextureWidth ) / mAppWindowWidth; +// y = ( y * mAppTextureHeight ) / mAppWindowHeight; + + // GLUT complains if I get the keyboard modifiers here, so just pretend there aren't any. + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, x, y, 0); + + // force a GLUT update + glutPostRedisplay(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyboard( unsigned char key ) + { + mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_DOWN, key, getModifiers()); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + int getAppWindowWidth() + { + return mAppWindowWidth; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + int getAppWindowHeight() + { + return mAppWindowHeight; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + std::string getAppWindowName() + { + return mAppWindowName; + }; + +}; + +mediaPluginTest* gApplication; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutReshape( int width, int height ) +{ + if ( gApplication ) + gApplication->reshape( width, height ); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutDisplay() +{ + if ( gApplication ) + gApplication->display(); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutIdle() +{ + if ( gApplication ) + gApplication->idle(); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutKeyboard( unsigned char key, int x, int y ) +{ + if ( key == 27 ) + { + delete gApplication; + exit( 0 ); + }; + + if ( gApplication ) + gApplication->keyboard( key ); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutMouseMove( int x, int y ) +{ + if ( gApplication ) + gApplication->mouseMove( x, y ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void glutMouseButton( int button, int state, int x, int y ) +{ + if ( gApplication ) + gApplication->mouseButton( button, state, x, y ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +int main( int argc, char* argv[] ) +{ + + ll_init_apr(); + + // Set up llerror logging + { + LLError::initForApplication("."); + LLError::setDefaultLevel(LLError::LEVEL_INFO); + } + + std::string launcher_name; + std::string plugin_name; + + if(argc >= 3) + { + launcher_name = argv[1]; + plugin_name = argv[2]; + } + else + { +#if LL_DARWIN + // hardcoding the testbed arguments by default + launcher_name = "plugin_process_host"; + plugin_name = "libdemo_media_plugin_quicktime.dylib"; +#elif LL_WINDOWS + // hardcoding the testbed arguments by default + launcher_name = "plugin_process_host.exe"; + plugin_name = "demo_media_plugin_quicktime.dll"; +#else + LL_ERRS("plugin_process_launcher") << "usage: " << argv[0] << " launcher_filename plugin_filename" << LL_ENDL; +#endif + } + + gApplication = new mediaPluginTest(launcher_name, plugin_name); + + if ( gApplication ) + { + glutInit( &argc, argv ); + glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB ); + + glutInitWindowPosition( 80, 0 ); + glutInitWindowSize( gApplication->getAppWindowWidth(), gApplication->getAppWindowHeight() ); + + glutCreateWindow( gApplication->getAppWindowName().c_str() ); + + glutKeyboardFunc( glutKeyboard ); + + glutMouseFunc( glutMouseButton ); + glutPassiveMotionFunc( glutMouseMove ); + glutMotionFunc( glutMouseMove ); + + glutDisplayFunc( glutDisplay ); + glutReshapeFunc( glutReshape ); + + glutIdleFunc( glutIdle ); + + gApplication->initGL(); + + glutMainLoop(); + + delete gApplication; + }; + + ll_cleanup_apr(); + + return 0; +} + diff --git a/linden/indra/test_apps/llplugintest/media_simple_test.cpp b/linden/indra/test_apps/llplugintest/media_simple_test.cpp new file mode 100644 index 000000000..9a60e8e6d --- /dev/null +++ b/linden/indra/test_apps/llplugintest/media_simple_test.cpp @@ -0,0 +1,460 @@ +/** + * @file demo_plugin.cpp + * @brief Test plugin to be loaded by the llplugin testbed. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include <string> +#include <iostream> +#include <stdlib.h> +#include <time.h> + +#if LL_DARWIN + #include <GLUT/glut.h> +#elif LL_LINUX + #include <GL/glut.h> +#else + #include "glut.h" +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +class mediaSource +{ + public: + //////////////////////////////////////////////////////////////////////////////// + // + mediaSource() : + mPixels( 0 ), + mIsDirty( false ), + mWidth( 200 ), + mHeight( 100 ), + mDepth( 3 ), + mPixelFormat( GL_BGR_EXT ) + { + mPixels = new unsigned char [ mWidth * mHeight * mDepth ]; + + for( int i = 0; i < mWidth * mHeight * mDepth; ++i ) + *( mPixels + i ) = rand() % 0x40; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void update() + { + const time_t interval = 1; + static time_t last_time = time( NULL ); + time_t cur_time = time( NULL ); + + if ( cur_time - last_time > interval ) + { + for( int i = 0; i < mWidth * mHeight * mDepth; ++i ) + *( mPixels + i ) = rand() % 0x40; + + mIsDirty = true; + + last_time = cur_time; + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ) + { + // make sure we don't write outside the buffer + if((x < 0) || (x >= mWidth) || (y < 0) || (y >= mHeight)) + return; + + *( mPixels + ( mHeight - y ) * mWidth * mDepth + x * mDepth + 0 ) = b; + *( mPixels + ( mHeight - y ) * mWidth * mDepth + x * mDepth + 1 ) = g; + *( mPixels + ( mHeight - y ) * mWidth * mDepth + x * mDepth + 2 ) = r; + + mIsDirty = true; + } + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseDown( int x, int y ) + { + write_pixel( x, y, 0xff, 0x00, 0x00 ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseUp( int x, int y ) + { + write_pixel( x, y, 0xff, 0xff, 0x00 ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseMove( int x, int y ) + { + write_pixel( x, y, 0xff, 0x00, 0xff ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyPress( unsigned char key ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // + int getWidth() { return mWidth; }; + int getHeight() { return mHeight; }; + int getDepth() { return mDepth; }; + int getPixelFormat() { return mPixelFormat; }; + bool isDirty() { return mIsDirty; }; + void ackDirty() { mIsDirty = false; }; + unsigned char* getPixels() { return mPixels; }; + + private: + unsigned char* mPixels; + bool mIsDirty; + int mWidth; + int mHeight; + int mDepth; + int mPixelFormat; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +class mediaSimpleTest +{ + public: + mediaSimpleTest() : + mAppWindowWidth( 800 ), + mAppWindowHeight( 600 ), + mAppTextureWidth( 0 ), + mAppTextureHeight( 0 ), + mAppTexture( 0 ), + mAppWindowName( "Media Simple Test" ), + mHomeUrl( "" ) + { + mMediaSource = new mediaSource; + + // calculate texture size required (next power of two above browser window size + for ( mAppTextureWidth = 1; mAppTextureWidth < mMediaSource->getWidth(); mAppTextureWidth <<= 1 ) {}; + for ( mAppTextureHeight = 1; mAppTextureHeight < mMediaSource->getHeight(); mAppTextureHeight <<= 1 ) {}; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + ~mediaSimpleTest() + { + delete mMediaSource; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void initGL() + { + // OpenGL initialization + glClearColor( 0.0f, 0.0f, 0.0f, 0.5f); + glEnable( GL_COLOR_MATERIAL ); + glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); + glEnable( GL_TEXTURE_2D ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glEnable( GL_CULL_FACE ); + + // create the texture used to display the browser data + glGenTextures( 1, &mAppTexture ); + glBindTexture( GL_TEXTURE_2D, mAppTexture ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexImage2D( GL_TEXTURE_2D, 0, + GL_RGB, + mAppTextureWidth, mAppTextureHeight, + 0, GL_RGB, GL_UNSIGNED_BYTE, 0 ); + } + + //////////////////////////////////////////////////////////////////////////////// + // + void reshape( int width, int height ) + { + if ( height == 0 ) + height = 1; + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + + glViewport( 0, 0, width, height ); + glOrtho( 0.0f, width, height, 0.0f, -1.0f, 1.0f ); + + // we use these values elsewhere so save + mAppWindowWidth = width; + mAppWindowHeight = height; + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + glutPostRedisplay(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void idle() + { + // lots of updates for smooth motion + glutPostRedisplay(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void display() + { + // clear screen + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + glLoadIdentity(); + + // use the browser texture + glBindTexture( GL_TEXTURE_2D, mAppTexture ); + + // needs to be updated? + mMediaSource->update(); + if ( mMediaSource->isDirty() ) + { + // grab the page + const unsigned char* pixels = mMediaSource->getPixels(); + if ( pixels ) + { + // write them into the texture + glTexSubImage2D( GL_TEXTURE_2D, 0, + 0, 0, + mMediaSource->getWidth(), + mMediaSource->getHeight(), + mMediaSource->getPixelFormat(), + GL_UNSIGNED_BYTE, + pixels ); + + // acknowledge we saw media was dirty and updated + mMediaSource->ackDirty(); + }; + }; + + // scale the texture so that it fits the screen + GLfloat texture_scale_x = ( GLfloat )mMediaSource->getWidth() / ( GLfloat )mAppTextureWidth; + GLfloat texture_scale_y = ( GLfloat )mMediaSource->getHeight() / ( GLfloat )mAppTextureHeight; + + // draw the single quad full screen (orthographic) + glMatrixMode( GL_TEXTURE ); + glPushMatrix(); + glScalef( texture_scale_x, texture_scale_y, 1.0f ); + + glEnable( GL_TEXTURE_2D ); + glColor3f( 1.0f, 1.0f, 1.0f ); + glBegin( GL_QUADS ); + glTexCoord2f( 1.0f, 1.0f ); + glVertex2d( mAppWindowWidth, 0 ); + + glTexCoord2f( 0.0f, 1.0f ); + glVertex2d( 0, 0 ); + + glTexCoord2f( 0.0f, 0.0f ); + glVertex2d( 0, mAppWindowHeight ); + + glTexCoord2f( 1.0f, .0f ); + glVertex2d( mAppWindowWidth, mAppWindowHeight ); + glEnd(); + + glMatrixMode( GL_TEXTURE ); + glPopMatrix(); + + glutSwapBuffers(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseButton( int button, int state, int x, int y ) + { + // texture is scaled to fit the screen so we scale mouse coords in the same way + x = ( x * mMediaSource->getWidth() ) / mAppWindowWidth; + y = ( y * mMediaSource->getHeight() ) / mAppWindowHeight; + + if ( button == GLUT_LEFT_BUTTON ) + { + if ( state == GLUT_DOWN ) + mMediaSource->mouseDown( x, y ); + else + if ( state == GLUT_UP ) + mMediaSource->mouseUp( x, y ); + }; + + // force a GLUT update + glutPostRedisplay(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseMove( int x , int y ) + { + // texture is scaled to fit the screen so we scale mouse coords in the same way + x = ( x * mMediaSource->getWidth() ) / mAppWindowWidth; + y = ( y * mMediaSource->getHeight() ) / mAppWindowHeight; + + mMediaSource->mouseMove( x, y ); + + // force a GLUT update + glutPostRedisplay(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyboard( unsigned char key ) + { + mMediaSource->keyPress( key ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + int getAppWindowWidth() + { + return mAppWindowWidth; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + int getAppWindowHeight() + { + return mAppWindowHeight; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + std::string getAppWindowName() + { + return mAppWindowName; + }; + + private: + int mAppWindowWidth; + int mAppWindowHeight; + mediaSource* mMediaSource; + int mAppTextureWidth; + int mAppTextureHeight; + GLuint mAppTexture; + std::string mAppWindowName; + std::string mHomeUrl; +}; + +mediaSimpleTest* gApplication; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutReshape( int width, int height ) +{ + if ( gApplication ) + gApplication->reshape( width, height ); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutDisplay() +{ + if ( gApplication ) + gApplication->display(); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutIdle() +{ + if ( gApplication ) + gApplication->idle(); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutKeyboard( unsigned char key, int x, int y ) +{ + if ( key == 27 ) + { + delete gApplication; + exit( 0 ); + }; + + if ( gApplication ) + gApplication->keyboard( key ); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutMouseMove( int x, int y ) +{ + if ( gApplication ) + gApplication->mouseMove( x, y ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void glutMouseButton( int button, int state, int x, int y ) +{ + if ( gApplication ) + gApplication->mouseButton( button, state, x, y ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +int main( int argc, char* argv[] ) +{ + gApplication = new mediaSimpleTest; + + if ( gApplication ) + { + glutInit( &argc, argv ); + glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB ); + + glutInitWindowPosition( 80, 0 ); + glutInitWindowSize( gApplication->getAppWindowWidth(), gApplication->getAppWindowHeight() ); + + glutCreateWindow( gApplication->getAppWindowName().c_str() ); + + glutKeyboardFunc( glutKeyboard ); + + glutMouseFunc( glutMouseButton ); + glutPassiveMotionFunc( glutMouseMove ); + glutMotionFunc( glutMouseMove ); + + glutDisplayFunc( glutDisplay ); + glutReshapeFunc( glutReshape ); + + glutIdleFunc( glutIdle ); + + gApplication->initGL(); + + glutMainLoop(); + + delete gApplication; + }; + + return 0; +} + diff --git a/linden/indra/test_apps/llplugintest/plugin_host.cpp b/linden/indra/test_apps/llplugintest/plugin_host.cpp new file mode 100644 index 000000000..5ba5d8b57 --- /dev/null +++ b/linden/indra/test_apps/llplugintest/plugin_host.cpp @@ -0,0 +1,92 @@ +/** + * @file plugin_host.cpp + * @brief Testbed for llplugin which directly loads a plugin dynamic library. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "linden_common.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llerrorcontrol.h" + +class MessageReceiver: public LLPluginInstanceMessageListener +{ + // Inherited from LLPluginInstanceMessageListener + /* virtual */ void receivePluginMessage(const std::string &message) + { + LL_INFOS("plugin_host") << "message received from plugin: " << message << LL_ENDL; + } + +}; + +int main(int argc, char **argv) +{ + ll_init_apr(); + + // Set up llerror logging + { + LLError::initForApplication("."); + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + } + + if(argc < 2) + { + LL_ERRS("plugin_host") << "usage: " << argv[0] << " plugin_filename" << LL_ENDL; + exit(1); + } + + std::string name = argv[1]; + + MessageReceiver receiver; + LLPluginInstance *plugin = new LLPluginInstance(&receiver); + if(plugin->load(name) == 0) + { + LLPluginMessage message; + message.setMessage("base", "init"); + message.setValue("foo", "1"); + message.setValue("bar", "2"); + plugin->sendMessage(message.generate()); + + message.setMessage("base", "idle"); + message.setValue("baz", "3"); + plugin->sendMessage(message.generate()); + + message.setMessage("base", "shutdown"); + plugin->sendMessage(message.generate()); + + plugin->idle(); + } + + delete plugin; + + ll_cleanup_apr(); +} + diff --git a/linden/indra/test_apps/llplugintest/plugin_process_launcher.cpp b/linden/indra/test_apps/llplugintest/plugin_process_launcher.cpp new file mode 100644 index 000000000..82b11e3c6 --- /dev/null +++ b/linden/indra/test_apps/llplugintest/plugin_process_launcher.cpp @@ -0,0 +1,197 @@ +/** + * @file plugin_process_launcher.cpp + * @brief Testbed for llplugin which launches the plugin loader shell. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llprocesslauncher.h" +#include "lltimer.h" // for ms_sleep() +#include "llpumpio.h" +#include "llapr.h" +#include "llerrorcontrol.h" +#include "llpluginprocessparent.h" + +class PluginProcessLauncherMessageReceiver : public LLPluginProcessParentOwner +{ +LOG_CLASS(PluginProcessLauncherMessageReceiver); + +public: + virtual ~PluginProcessLauncherMessageReceiver() + { + } + + /* virtual */ void receivePluginMessage(const LLPluginMessage &message) + { + LL_INFOS("plugin_process_launcher") << "received message: \n" << message.generate() << LL_ENDL; + } +}; + +LLPumpIO* gServicePump; +LLPluginProcessParent *gPlugin; + + +#define SHARED_MEMORY_SIZE 0x10000 +#define SHARED_MEMORY_NAME "testsegment" +enum State +{ + STATE_STARTUP, + STATE_ADD_MEMORY, + STATE_RUNNING, + STATE_REMOVE_MEMORY, + STATE_SHUTDOWN, + STATE_CLEANUP, + STATE_DONE +}; + +int main(int argc, char **argv) +{ + ll_init_apr(); + + // Set up llerror logging + { + LLError::initForApplication("."); + LLError::setDefaultLevel(LLError::LEVEL_INFO); + } + + std::string launcher_name; + std::string plugin_name; + + if(argc >= 3) + { + launcher_name = argv[1]; + plugin_name = argv[2]; + } + else + { +#if LL_DARWIN + // hardcoding the testbed arguments by default + launcher_name = "plugin_process_host"; + plugin_name = "libdemo_plugin.dylib"; +#elif LL_WINDOWS + // hardcoding the testbed arguments by default + launcher_name = "plugin_process_host.exe"; + plugin_name = "demo_plugin.dll"; +#else + LL_ERRS("plugin_process_launcher") << "usage: " << argv[0] << " launcher_filename plugin_filename" << LL_ENDL; +#endif + } + + PluginProcessLauncherMessageReceiver receiver; + + gServicePump = new LLPumpIO(gAPRPoolp); + gServicePump->prime(gAPRPoolp); + + gPlugin = new LLPluginProcessParent(gServicePump, &receiver); + + State state = STATE_STARTUP; + while(state != STATE_DONE) + { + switch(state) + { + case STATE_STARTUP: + LL_INFOS("plugin_process_launcher") << "startup" << LL_ENDL; + gPlugin->init(launcher_name, plugin_name); + state = STATE_ADD_MEMORY; + break; + + case STATE_ADD_MEMORY: + if(gPlugin->isRunning()) + { + LL_INFOS("plugin_process_launcher") << "adding shared memory" << LL_ENDL; + gPlugin->addSharedMemory(SHARED_MEMORY_SIZE); + state = STATE_RUNNING; + } + break; + + case STATE_RUNNING: + { + volatile unsigned char *addr = (unsigned char*)gPlugin->getSharedMemoryAddress(SHARED_MEMORY_NAME); + if(addr != NULL) + { + int val = (int)(addr[0]); + if(val >= 16) + { + state = STATE_REMOVE_MEMORY; + } + else + { + LL_INFOS("plugin_process_launcher") << "running, value from shared memory is " << val << LL_ENDL; + } + } + } + break; + + case STATE_REMOVE_MEMORY: + LL_INFOS("plugin_process_launcher") << "removing shared memory" << LL_ENDL; + gPlugin->removeSharedMemory(SHARED_MEMORY_NAME); + state = STATE_SHUTDOWN; + break; + + case STATE_SHUTDOWN: + { + volatile unsigned char *addr = (unsigned char*)gPlugin->getSharedMemoryAddress(SHARED_MEMORY_NAME); + if(addr == NULL) + { + LL_INFOS("plugin_process_launcher") << "sending shutdown request" << LL_ENDL; + gPlugin->shutdownRequest(); + state = STATE_CLEANUP; + } + } + break; + + case STATE_CLEANUP: + if(gPlugin->isDone()) + { + LL_INFOS("plugin_process_launcher") << "plugin is done" << LL_ENDL; + state = STATE_DONE; + } + break; + + case STATE_DONE: + // should never reach here -- the while() should exit first. + break; + } + + // Do this every time through the loop + if(state != STATE_DONE) + { + gServicePump->pump(); + gServicePump->callback(); + gPlugin->idle(); + ms_sleep(100); + } + } + + delete gPlugin; + + ll_cleanup_apr(); + +} diff --git a/linden/indra/win_crash_logger/StdAfx.h b/linden/indra/win_crash_logger/StdAfx.h index 021a995f5..79198c256 100644 --- a/linden/indra/win_crash_logger/StdAfx.h +++ b/linden/indra/win_crash_logger/StdAfx.h @@ -46,6 +46,8 @@ // Windows Header Files: +# define WIN32_LEAN_AND_MEAN +# include <winsock2.h> #include <windows.h> // C RunTime Header Files diff --git a/linden/indra/win_crash_logger/llcrashloggerwindows.h b/linden/indra/win_crash_logger/llcrashloggerwindows.h index e6a9c77d5..f2a877e25 100644 --- a/linden/indra/win_crash_logger/llcrashloggerwindows.h +++ b/linden/indra/win_crash_logger/llcrashloggerwindows.h @@ -34,6 +34,8 @@ #define LLCRASHLOGGERWINDOWS_H #include "llcrashlogger.h" +# define WIN32_LEAN_AND_MEAN +# include <winsock2.h> #include "windows.h" #include "llstring.h" diff --git a/linden/indra/win_updater/updater.cpp b/linden/indra/win_updater/updater.cpp index 503127082..c6fa3c8dc 100644 --- a/linden/indra/win_updater/updater.cpp +++ b/linden/indra/win_updater/updater.cpp @@ -39,6 +39,8 @@ // *TODO: Switch to fopen_s, strtok_s, etc. #define _CRT_SECURE_NO_DEPRECATE +# define WIN32_LEAN_AND_MEAN +# include <winsock2.h> #include <windows.h> #include <wininet.h> #include <stdio.h> diff --git a/linden/install.xml b/linden/install.xml index 2a5ecf836..7fda398ca 100755 --- a/linden/install.xml +++ b/linden/install.xml @@ -74,13 +74,13 @@ <key>url</key> <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/SDL-1.2.5-linux-i686-gcc-4.1-20080915.tar.bz2</uri> </map> - <key>linux64</key> - <map> - <key>md5sum</key> - <string>214fe53a11b3cdef115d36cb95aae185</string> - <key>url</key> - <uri>http://imprudenceviewer.org/download/libs/SDL-1.2.12-linux64-20091230.tar.bz2</uri> - </map> + <key>linux64</key> + <map> + <key>md5sum</key> + <string>214fe53a11b3cdef115d36cb95aae185</string> + <key>url</key> + <uri>http://imprudenceviewer.org/download/libs/SDL-1.2.12-linux64-20091230.tar.bz2</uri> + </map> <key>windows</key> <map> <key>md5sum</key> @@ -99,9 +99,9 @@ <key>darwin</key> <map> <key>md5sum</key> - <string>abd07d760cdc7d23da3b861f34b09c92</string> + <string>115d8ac44a91efdb173e9b3e478c46b6</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.2.8-darwin-20080812.tar.bz2</uri> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.3.7-darwin-20090805.tar.bz2</uri> </map> <key>linux</key> <map> @@ -120,9 +120,9 @@ <key>windows</key> <map> <key>md5sum</key> - <string>b9d23a69a25fdeed96dcc3bf696b6514</string> + <string>a02619c1e30a3db02d3883bf1ad7a1e6</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.2.12-windows-20080806.tar.bz2</uri> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.3.8-windows-20090911.tar.bz2</uri> </map> </map> </map> @@ -176,33 +176,12 @@ <string>creative commons attribution-share alike 3.0</string> <key>packages</key> <map> - <key>darwin</key> - <map> - <key>md5sum</key> - <string>506d8203676998eab8ccbaaf7bc7415f</string> - <key>url</key> - <uri>http://imprudenceviewer.org/download/extras/imprudence-artwork-20101017.tar.bz2</uri> - </map> - <key>linux</key> - <map> - <key>md5sum</key> - <string>506d8203676998eab8ccbaaf7bc7415f</string> - <key>url</key> - <uri>http://imprudenceviewer.org/download/extras/imprudence-artwork-20101017.tar.bz2</uri> - </map> - <key>linux64</key> - <map> - <key>md5sum</key> - <string>506d8203676998eab8ccbaaf7bc7415f</string> - <key>url</key> - <uri>http://imprudenceviewer.org/download/extras/imprudence-artwork-20101017.tar.bz2</uri> - </map> - <key>windows</key> + <key>common</key> <map> <key>md5sum</key> - <string>506d8203676998eab8ccbaaf7bc7415f</string> + <string>a2cde4f24bdcc260b661e139846b8acd</string> <key>url</key> - <uri>http://imprudenceviewer.org/download/extras/imprudence-artwork-20101017.tar.bz2</uri> + <uri>http://imprudenceviewer.org/download/libs/imprudence-artwork-20101026.tar.bz2</uri> </map> </map> </map> @@ -295,7 +274,7 @@ </map> </map> </map> - <key>dbghelp</key> + <key>dbghelp</key> <map> <key>copyright</key> <string>Copyright Microsoft Corporation</string> @@ -327,9 +306,9 @@ <key>linux</key> <map> <key>md5sum</key> - <string>eb25444142d4102b0ce1b7ffaadb071e</string> + <string>5bbf7e33dadc7d046dcf44883a9ec3d0</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/dbusglib-linux-20080707.tar.bz2</uri> + <uri>http://imprudenceviewer.org/download/libs/dbusglib-linux-20101031.tar.bz2</uri> </map> <key>linux64</key> <map> @@ -375,9 +354,9 @@ <key>darwin</key> <map> <key>md5sum</key> - <string>9c5603e328e9f543e0a599d6b25be973</string> + <string>c457a0a041ac4946265889a503d26c3d</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-darwin-20080812.tar.bz2</uri> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-darwin-20090805.tar.bz2</uri> </map> <key>linux</key> <map> @@ -483,6 +462,21 @@ </map> </map> </map> + <key>freeglut</key> + <map> + <key>license</key> + <string>mit</string> + <key>packages</key> + <map> + <key>windows</key> + <map> + <key>md5sum</key> + <string>fcbb695ff203775fad96d184bf5f34fc</string> + <key>url</key> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freeglut-2.4.0-windows-20090608.tar.bz2</uri> + </map> + </map> + </map> <key>freetype</key> <map> <key>copyright</key> @@ -601,6 +595,28 @@ </map> </map> </map> + <key>glui</key> + <map> + <key>license</key> + <string>lgpl</string> + <key>packages</key> + <map> + <key>darwin</key> + <map> + <key>md5sum</key> + <string>84f792a860691d0fad6d1de6eeb31baa</string> + <key>url</key> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glui-2.36-darwin-20090623a.tar.bz2</uri> + </map> + <key>windows</key> + <map> + <key>md5sum</key> + <string>5b8631fe510d4ebaeb965c673937e1e7</string> + <key>url</key> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glui-2.3.6-windows-freeglut-20090608.tar.bz2</uri> + </map> + </map> + </map> <key>google</key> <map> <key>license</key> @@ -650,15 +666,8 @@ <key>url</key> <uri>http://imprudenceviewer.org/download/libs/gstreamer-0.10.24-linux64-20091230.tar.bz2</uri> </map> - <key>windows</key> - <map> - <key>md5sum</key> - <string>da6c3fd73a7e5c9bef768edab8a38c2f</string> - <key>url</key> - <uri>http://imprudenceviewer.org/download/libs/gstreamer-0.10.22-windows-20100825.tar.bz2</uri> </map> </map> - </map> <key>gstreamer-plugins</key> <map> <key>license</key> @@ -672,29 +681,8 @@ <key>url</key> <uri>http://imprudenceviewer.org/download/libs/gstreamer-plugins-darwin-20100826.tar.bz2</uri> </map> - <key>linux</key> - <map> - <key>md5sum</key> - <string>973aabcba37f6ee0ceab2e3d063eea84</string> - <key>url</key> - <uri>http://imprudenceviewer.org/download/libs/gstreamer-plugins-linux-20100827.tar.bz2</uri> </map> - <key>linux64</key> - <map> - <key>md5sum</key> - <string>663c29f3885ab8429ad6841d80181c31</string> - <key>url</key> - <uri>http://imprudenceviewer.org/download/libs/gstreamer-plugins-linux64-20100827.tar.bz2</uri> - </map> - <key>windows</key> - <map> - <key>md5sum</key> - <string>a5c7e5f2dbd5ed247f6e9c54f03a8b42</string> - <key>url</key> - <uri>http://imprudenceviewer.org/download/libs/gstreamer-plugins-windows-20100825.tar.bz2</uri> </map> - </map> - </map> <key>gtk-etc</key> <map> <key>copyright</key> @@ -712,9 +700,9 @@ cairo: Copyright © 2002 University of Southern California, Copyright © 2005 Re <key>linux</key> <map> <key>md5sum</key> - <string>57ec243cf8e05e4fb7c737846a287498</string> + <string>349ee367e0ac1e878b24b66e449c6ff8</string> <key>url</key> - <uri>http://imprudenceviewer.org/download/libs/gtk-etc-linux32-dbg-20100604.tar.bz2</uri> + <uri>http://imprudenceviewer.org/download/libs/gtk-etc-linux-20101106.1.tar.bz2</uri> </map> <key>linux64</key> <map> @@ -806,7 +794,7 @@ cairo: Copyright © 2002 University of Southern California, Copyright © 2005 Re </map> <key>linux64</key> <map> - <key>md5sum</key> + <key>md5sum</key> <string>64e7fa98568ef52b3b9d4a18b3515090</string> <key>url</key> <uri>http://imprudenceviewer.org/download/libs/jpeglib-7-linux64-20091230.tar.bz2</uri> @@ -1039,39 +1027,39 @@ Portions copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura </map> </map> </map> - <key>llmozlib</key> + <key>llqtwebkit</key> <map> <key>license</key> - <string>mozillaPL</string> + <string>lgpl</string> <key>packages</key> <map> <key>darwin</key> <map> <key>md5sum</key> - <string>c951587726618d33646f2b169c290bd3</string> + <string>becffca6bd8dcb239de284ea2a8b485b</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llmozlib-2_0_0_21-darwin-20090304.tar.bz2</uri> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-4.6+cookies-darwin-20100617.tar.bz2</uri> </map> <key>linux</key> <map> <key>md5sum</key> - <string>b7ebcf0fb764ed4fa57c62d068b4a769</string> + <string>5d743c93b970abe685b185de83001a6e</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llmozlib-linux-20090304prfhk.tar.bz2</uri> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-linux-qt4.6-20100923.tar.bz2</uri> </map> <key>linux64</key> - <map> - <key>md5sum</key> - <string>afa946a118d3d71123003785189a31f2</string> - <key>url</key> - <uri>http://imprudenceviewer.org/download/libs/llmozlib-linux64-20091231.tar.bz2</uri> - </map> + <map> + <key>md5sum</key> + <string>d5deaf897fe8effa3d3537c875060379</string> + <key>url</key> + <uri>http://imprudenceviewer.org/download/libs/llqtwebkit-linux64-20100907.tar.bz2</uri> + </map> <key>windows</key> <map> <key>md5sum</key> - <string>e9454e258b99668782d8570481b5eda1</string> + <string>df1bdd683128e060d60e435f65d8f7e8</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llmozlib-windows-20090306.tar.bz2</uri> + <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-windows-qt4.6-20100617.tar.bz2</uri> </map> </map> </map> @@ -1338,6 +1326,84 @@ Copyright (C) 2004-2005 Vladimir Berezniker @ http://public.xdi.org/=vmpn </map> </map> </map> + <key>pulseaudio</key> + <map> + <key>copyright</key> + <string>Copyright 2004-2006 Lennart Poettering, Copyright 2006 Pierre Ossman (ossman@cendio.se) for Cendio AB</string> + <key>description</key> + <string>pulseaudio: headers only</string> + <key>license</key> + <string>lgpl</string> + <key>packages</key> + <map> + <key>linux</key> + <map> + <key>md5sum</key> + <string>30cb00069fe2a545fbf7be1070386236</string> + <key>url</key> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/linux-pulse-headers-0.9.14.tar.bz2</uri> + </map> + <key>linux64</key> + <map> + <key>md5sum</key> + <string>30cb00069fe2a545fbf7be1070386236</string> + <key>url</key> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/linux-pulse-headers-0.9.14.tar.bz2</uri> + </map> + </map> + </map> + <key>quicktime</key> + <map> + <key>copyright</key> + <string>Copyright (C) 1990-2006 by Apple Computer, Inc., all rights reserved.</string> + <key>description</key> + <string>Separate download. Used to play in-world video clips on a prim. </string> + <key>license</key> + <string>quicktime</string> + <key>packages</key> + <map> + <key>windows</key> + <map> + <key>md5sum</key> + <string>7a2e6fc89b1ef027f3a36ebb46fb0c8a</string> + <key>url</key> + <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/quicktime-windows-20080611.tar.bz2</uri> + </map> + </map> + </map> + <key>smartheap</key> + <map> + <key>copyright</key> + <string>Copyright (C) 1991-2000 Compuware Corporation. All Rights Reserved.</string> + <key>description</key> + <string>Memory Management Library</string> + <key>license</key> + <string>smartheap</string> + <key>packages</key> + <map> + <key>darwin</key> + <map> + <key>md5sum</key> + <string>f54131b5f228e805c64c2e4e6c96579a</string> + <key>url</key> + <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-darwin-20080610.tar.bz2</uri> + </map> + <key>linux</key> + <map> + <key>md5sum</key> + <string>499208522bf7d7843e1d014d64214e06</string> + <key>url</key> + <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-linux-20080610.tar.bz2</uri> + </map> + <key>windows</key> + <map> + <key>md5sum</key> + <string>78fd47017f21d11eae43bca3e38a3e1e</string> + <key>url</key> + <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-windows-20080611.tar.bz2</uri> + </map> + </map> + </map> <key>theora</key> <map> <key>copyright</key> @@ -1563,7 +1629,7 @@ Copyright (C) 2004-2005 Vladimir Berezniker @ http://public.xdi.org/=vmpn <key>url</key> <string>http://www.xfree86.org/4.4.0/LICENSE9.html#sgi</string> </map> - <key>MSDTW</key> + <key>MSDTW</key> <map> <key>text</key> <string>MICROSOFT SOFTWARE LICENSE TERMS @@ -1770,12 +1836,12 @@ Cass Everitt - cass@r3.nu <key>text</key> <string>on file</string> </map> - <key>hunspell</key> + <key>hunspell</key> <map> <key>url</key> <string>http://www.gnu.org/licenses/gpl.html</string> </map> - <key>hunspell-dictionaries</key> + <key>hunspell-dictionaries</key> <map> <key>url</key> <string>http://www.gnu.org/licenses/gpl.html</string> @@ -1791,13 +1857,13 @@ Cass Everitt - cass@r3.nu <key>text</key> <string>http://nyctergatis.com/jpeglib/</string> </map> - <key>jsoncpp</key> - <map> - <key>text</key> - <string>The json-cpp library and this documentation are in Public Domain. Retrieved from http://jsoncpp.sourceforge.net/ on 2009-09-04.</string> - <key>url</key> - <string>http://jsoncpp.sourceforge.net</string> - </map> + <key>jsoncpp</key> + <map> + <key>text</key> + <string>The json-cpp library and this documentation are in Public Domain. Retrieved from http://jsoncpp.sourceforge.net/ on 2009-09-04.</string> + <key>url</key> + <string>http://jsoncpp.sourceforge.net</string> + </map> <key>kdu</key> <map> <key>text</key> @@ -1838,11 +1904,6 @@ Cass Everitt - cass@r3.nu <key>text</key> <string>Multiple licenses. See package contents for details.</string> </map> - <key>mozillaPL</key> - <map> - <key>url</key> - <string>http://www.mozilla.org/MPL/MPL-1.1.html</string> - </map> <key>xiph-bsd</key> <map> <key>url</key> diff --git a/linden/scripts/install.py b/linden/scripts/install.py index a16034f9d..f09fc4818 100755 --- a/linden/scripts/install.py +++ b/linden/scripts/install.py @@ -534,24 +534,24 @@ def _build_ifiles(self, platform, cache_dir): platform, cache_dir)) to_install = [] + to_uninstall = [] #print "self._installed",self._installed for ifile in ifiles: if ifile.pkgname not in self._installed: to_install.append(ifile) elif ifile.url not in self._installed[ifile.pkgname].urls(): + to_uninstall.append(ifile.pkgname) to_install.append(ifile) elif ifile.md5sum != \ self._installed[ifile.pkgname].get_md5sum(ifile.url): - # *TODO: We may want to uninstall the old version too - # when we detect it is installed, but the md5 sum is - # different. + to_uninstall.append(ifile.pkgname) to_install.append(ifile) else: #print "Installation up to date:", # ifile.pkgname,ifile.platform_path pass #print "to_install",to_install - return to_install + return [to_install, to_uninstall] def _install(self, to_install, install_dir): for ifile in to_install: @@ -620,12 +620,17 @@ def install(self, installables, platform, install_dir, cache_dir): cache_dir = os.path.realpath(cache_dir) _mkdir(install_dir) _mkdir(cache_dir) - to_install = self._build_ifiles(platform, cache_dir) + to_install_uninstall = self._build_ifiles(platform, cache_dir) + to_install = to_install_uninstall[0] + to_uninstall = to_install_uninstall[1] # Filter for files which we actually requested to install. to_install = [ifl for ifl in to_install if ifl.pkgname in installables] + to_uninstall = [ifl for ifl in to_uninstall if ifl in installables] for ifile in to_install: ifile.fetch_local() + if to_uninstall: + self.uninstall(to_uninstall, install_dir) self._install(to_install, install_dir) def do_install(self, installables, platform, install_dir, cache_dir=None,