diff --git a/.gitignore b/.gitignore
index 4b9a7a4cd6..b47f28773e 100755
--- a/.gitignore
+++ b/.gitignore
@@ -111,3 +111,5 @@ compile_commands.json
# ignore tracy for now
indra/tracy
firestorm.code-workspace
+
+.cache/clangd/index/
diff --git a/BuildParams b/BuildParams
index 27ae40767a..dda25e3e63 100644
--- a/BuildParams
+++ b/BuildParams
@@ -16,6 +16,9 @@ build_Linux_Doxygen = true
# Need viewer-build-variables as well as other shared repositories
buildscripts_shared_more_NAMEs="build_secrets build_variables git_hooks"
+# Python 3 / SL-15742
+BUILDSCRIPTS_PY3 = "true"
+
################################################################
#### Examples of how to set the viewer_channel ####
#
@@ -36,6 +39,7 @@ buildscripts_shared_more_NAMEs="build_secrets build_variables git_hooks"
################################################################
viewer_channel = "Second Life Test"
+
################################################################
# Special packaging parameters.
# These parameters can be used to create additional packages
diff --git a/README_BUILD_FIRESTORM_LINUX.txt b/README_BUILD_FIRESTORM_LINUX.txt
index 2e856043a1..3aa979da25 100755
--- a/README_BUILD_FIRESTORM_LINUX.txt
+++ b/README_BUILD_FIRESTORM_LINUX.txt
@@ -1,4 +1,4 @@
-First, make sure gcc-5.4 and g++-5.4 are installed.
+First, make sure gcc-7.5.0 and g++-7.5.0 are installed.
If you want to use licensed FMOD or KDU build libraries (they are optional) you have to provision these yourself.
If you're licensing these with Phoenix/Firestorm, ask for the libraries for fmod and kdu. Put them into:
@@ -27,6 +27,12 @@ Other examples:
autobuild build -A64 -c ReleaseFS --no-configure -- --clean # Clean rebuild
autobuild build -A64 -c ReleaseFS -- --package # Complete a build and package it into a tarball
+When using the --package switch you can set the XZ_DEFAULTS variable to -T0 to use all available CPU cores
+to create the .tar.xz file. This can significantly reduce the time needed to create the archive, but it will
+use a lot more memory. For example:
+ export XZ_DEFAULTS="-T0"
+ autobuild build -A64 -c ReleaseFS_open -- --package
+
If you want to build with clang you can call autobuild like this:
CC=clang CXX=clang++ autobuild configure -A64 -c ReleaseFS
diff --git a/autobuild.xml b/autobuild.xml
index c66dde9b47..9f3a56a688 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -3,6 +3,118 @@
llphysicsextensions_source
@@ -2473,9 +2491,9 @@
archive
hash
- 14fac452271ebfba37ba5ddcf5bffa54
+ da57838d80cf332f4a3026713a13f086
url
- http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54842/510078/llphysicsextensions_source-1.0.538972-darwin64-538972.tar.bz2
+ https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/90708/824484/llphysicsextensions_source-1.0.565754-darwin64-565754.tar.bz2
name
darwin64
@@ -2497,16 +2515,16 @@
archive
hash
- f3c066c1aebed8a6519a3e5ce64b9a3c
+ 28ad884012aa0bb70cf4101853af2f9a
url
- http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54982/511796/llphysicsextensions_source-1.0.538972-windows-538972.tar.bz2
+ https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/90733/824570/llphysicsextensions_source-1.0.565768-windows-565768.tar.bz2
name
windows
version
- 1.0.538972
+ 1.0.565768
llphysicsextensions_stub
@@ -3424,9 +3442,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- c42575ac8997de979eadb082c33a578e
+ b97d0f6570104277de92d0d3f2d1111d
url
- https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81322/765512/uriparser-0.9.4-darwin64-559132.tar.bz2
+ https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89474/816487/uriparser-0.9.4-darwin64-564957.tar.bz2
name
darwin64
@@ -3460,9 +3478,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 901b1063556fc6b2575e745eef2bf744
+ e2600c798e220cc98c1cc77341aee00d
url
- https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81323/765528/uriparser-0.9.4-windows-559132.tar.bz2
+ https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89476/816496/uriparser-0.9.4-windows-564957.tar.bz2
name
windows
@@ -3472,9 +3490,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 962c01d553f286c430102998129fb0d6
+ 50d857117d31844fc8b84b07b795fd00
url
- https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81324/765527/uriparser-0.9.4-windows64-559132.tar.bz2
+ https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89475/816497/uriparser-0.9.4-windows64-564957.tar.bz2
name
windows64
@@ -3502,9 +3520,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- a3c8357a2f5a62cd7de43181b02553bc
+ 33ed1bb3e24fbd3462da04fb3e917e94
url
- https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/91396/829032/viewer_manager-2.0.566227-darwin64-566227.tar.bz2
+ https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/94814/850320/viewer_manager-3.0.568552-darwin64-568552.tar.bz2
name
darwin64
@@ -3538,9 +3556,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 0654b449d9bdf3507664cf5caa67336f
+ 2ad8e04965ac8bddb7d351abe09bee07
url
- https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/91397/829041/viewer_manager-2.0.566227-windows-566227.tar.bz2
+ https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/94813/850316/viewer_manager-3.0.568552-windows-568552.tar.bz2
name
windows
@@ -3551,7 +3569,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
source_type
hg
version
- 2.0.566227
+ 3.0.568552
vlc-bin
@@ -3577,30 +3595,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
name
darwin64
- linux
-
- archive
-
- hash
- 9f9582031af3b78d6153ec296d6dde9f
- url
- http://3p.firestormviewer.org/vlc_bin-2.2.3-linux-201607071822-r16.tar.bz2
-
- name
- linux
-
- linux64
-
- archive
-
- hash
- 5eace400c487011a678493fc520be24d
- url
- http://3p.firestormviewer.org/vlc_bin-2.2.3-linux-x64-201610182130-r16.tar.bz2
-
- name
- linux64
-
windows
archive
diff --git a/doc/contributions.txt b/doc/contributions.txt
index efe6e933e4..1f3ad67bb1 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -281,6 +281,7 @@ Beq Janus
SL-14766
SL-14927
SL-11300
+ SL-16021
Beth Walcher
Bezilon Kasei
Biancaluce Robbiani
@@ -1113,6 +1114,7 @@ Nicky Dasmijn
OPEN-187
STORM-1937
OPEN-187
+ SL-15234
STORM-2010
STORM-2082
MAINT-6665
@@ -1122,6 +1124,7 @@ Nicky Dasmijn
SL-11072
SL-13141
SL-13642
+ SL-16438
Nicky Perian
OPEN-1
STORM-1087
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 9d76be92c8..646ff1cfa2 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -112,6 +112,10 @@ if (NOT USE_BUGSPLAT)
add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger)
endif (NOT USE_BUGSPLAT)
+if( LINUX )
+ add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
+endif()
+
add_subdirectory(${LIBS_OPEN_PREFIX}llplugin)
add_subdirectory(${LIBS_OPEN_PREFIX}llui)
add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components)
@@ -159,6 +163,10 @@ endif (USE_BUGSPLAT)
add_subdirectory(${VIEWER_PREFIX}newview)
add_dependencies(viewer firestorm-bin)
+set_target_properties(
+ firestorm-bin PROPERTIES
+ VS_DEBUGGER_WORKING_DIRECTORY "..\\..\\indra\\newview")
+
add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL)
if (LL_TESTS)
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 6909a94e4b..fe319a587b 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -165,11 +165,6 @@ endif (WINDOWS)
if (LINUX)
set(CMAKE_SKIP_RPATH TRUE)
-
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0.0 )
- message( FATAL_ERROR "GCC greater 9.4.0 is not supported. Recompile boost for support of GCC 10.0.0 and up." )
- endif()
-
#
# And another hack for FORTIFY_SOURCE. Some distributions (for example Gentoo) define FORTIFY_SOURCE by default.
# Check if this is the case, if yes, do not define it again.
@@ -225,10 +220,6 @@ if (LINUX)
endif (NOT USESYSTEMLIBS)
set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG}")
-
- if( NOT (CMAKE_CXX_COMPILER MATCHES ".*clang") )
- set( CMAKE_CXX_FLAGS "-fabi-version=9 ${CMAKE_CXX_FLAGS}" )
- endif()
endif (LINUX)
diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake
index 3406e5fd15..ef67f9af90 100644
--- a/indra/cmake/BuildVersion.cmake
+++ b/indra/cmake/BuildVersion.cmake
@@ -19,34 +19,23 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n
message(STATUS "Revision (from autobuild environment): ${VIEWER_VERSION_REVISION}")
else (DEFINED ENV{revision})
- find_program(MERCURIAL hg)
- find_program(SED sed)
- if (DEFINED MERCURIAL AND DEFINED SED)
+ find_program(GIT git)
+ if (DEFINED GIT )
execute_process(
- # FIRE-11737: Reverting to old revisions shows tip in build string
- # This command gets the revision number of the current
- # repository tip. This leads to confusion when
- # building an earlier revision. Instead, we use
- # "hg identify -n" to get the local revision number
- # of the actual state of the repository.
- #COMMAND ${MERCURIAL} log -r tip:0 --template '\\n'
- #COMMAND ${WORDCOUNT} -l
- #COMMAND ${SED} "s/ //g"
- COMMAND ${MERCURIAL} identify -n
- COMMAND ${SED} "s/+//" # [CR] Strip off any + from the revision number
+ COMMAND ${GIT} rev-list --count HEAD
OUTPUT_VARIABLE VIEWER_VERSION_REVISION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
- message(STATUS "Revision (from hg) ${VIEWER_VERSION_REVISION}")
+ message(STATUS "Revision (from git) ${VIEWER_VERSION_REVISION}")
else ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
message(STATUS "Revision not set (repository not found?); using 0")
set(VIEWER_VERSION_REVISION 0 )
endif ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
- else (DEFINED MERCURIAL AND DEFINED SED)
- message(STATUS "Revision not set: 'hg' or 'sed' not found; using 0")
+ else (DEFINED GIT )
+ message(STATUS "Revision not set: 'git' found; using 0")
set(VIEWER_VERSION_REVISION 0)
- endif (DEFINED MERCURIAL AND DEFINED SED)
+ endif (DEFINED GIT)
endif (DEFINED ENV{revision})
message(STATUS "Building '${VIEWER_CHANNEL}' Version ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
else ( EXISTS ${VIEWER_VERSION_BASE_FILE} )
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 74d32defea..2d4031d101 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -20,7 +20,7 @@ set(cmake_SOURCE_FILES
ConfigurePkgConfig.cmake
CURL.cmake
Copy3rdPartyLibs.cmake
- DBusGlib.cmake
+ GLIB.cmake
DeploySharedLibs.cmake
Discord.cmake # Discord rich presence
DragDrop.cmake
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index c262d7f209..519f68b53e 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -245,16 +245,9 @@ elseif(LINUX)
# have to deal with
if (NOT USESYSTEMLIBS)
set(release_files
- #libapr-1.so.0
- #libaprutil-1.so.0
- libatk-1.0.so
#libdb-5.1.so
${EXPAT_COPY}
- #libfreetype.so.6.6.2
- #libfreetype.so.6
#libGLOD.so
- libgmodule-2.0.so
- libgobject-2.0.so
libhunspell-1.3.so.0.0.0
libopenal.so
#libopenjpeg.so
diff --git a/indra/cmake/DBusGlib.cmake b/indra/cmake/DBusGlib.cmake
deleted file mode 100644
index 5e46b6711a..0000000000
--- a/indra/cmake/DBusGlib.cmake
+++ /dev/null
@@ -1,29 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-if (USESYSTEMLIBS)
- include(FindPkgConfig)
-
- pkg_check_modules(DBUSGLIB REQUIRED dbus-glib-1)
-
-elseif (LINUX)
- use_prebuilt_binary(dbus_glib)
- set(DBUSGLIB_FOUND ON FORCE BOOL)
- set(DBUSGLIB_INCLUDE_DIRS
- ${LIBS_PREBUILT_DIR}/include/dbus
- )
- # We don't need to explicitly link against dbus-glib itself, because
- # the viewer probes for the system's copy at runtime.
- set(DBUSGLIB_LIBRARIES
- gobject-2.0
- glib-2.0
- )
-endif (USESYSTEMLIBS)
-
-if (DBUSGLIB_FOUND)
- set(DBUSGLIB ON CACHE BOOL "Build with dbus-glib message bus support.")
-endif (DBUSGLIB_FOUND)
-
-if (DBUSGLIB)
- add_definitions(-DLL_DBUS_ENABLED=1)
-endif (DBUSGLIB)
diff --git a/indra/cmake/FreeType.cmake b/indra/cmake/FreeType.cmake
index df267985c4..79159843e1 100644
--- a/indra/cmake/FreeType.cmake
+++ b/indra/cmake/FreeType.cmake
@@ -9,7 +9,11 @@ else (USESYSTEMLIBS)
use_prebuilt_binary(freetype)
set(FREETYPE_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
set(FREETYPE_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/freetype2) # Also add freetype2 to search dir, or some includes will fail.
- set(FREETYPE_LIBRARIES freetype)
+ # Linux links this via UI.cmake
+ if( NOT LINUX )
+ set(FREETYPE_LIBRARIES freetype)
+ endif()
+ #
endif (USESYSTEMLIBS)
link_directories(${FREETYPE_LIBRARY_DIRS})
diff --git a/indra/cmake/GLIB.cmake b/indra/cmake/GLIB.cmake
new file mode 100644
index 0000000000..186195e078
--- /dev/null
+++ b/indra/cmake/GLIB.cmake
@@ -0,0 +1,11 @@
+
+include(Prebuilt)
+
+if( LINUX )
+ use_prebuilt_binary(glib)
+ set(GLIB_FOUND ON CACHE BOOL "Build against glib 2")
+ set(GLIB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/glib-2.0 ${LIBS_PREBUILT_DIR}/lib/release/glib-2.0/include )
+ set(GLIB_LIBRARIES libgobject-2.0.a libglib-2.0.a libffi.a libpcre.a)
+ set(GIO_LIBRARIES libgio-2.0.a libgmodule-2.0.a -lresolv ${GLIB_LIBRARIES} )
+ add_definitions(-DLL_GLIB=1)
+endif()
diff --git a/indra/cmake/GStreamer10Plugin.cmake b/indra/cmake/GStreamer10Plugin.cmake
new file mode 100644
index 0000000000..ded45da610
--- /dev/null
+++ b/indra/cmake/GStreamer10Plugin.cmake
@@ -0,0 +1,32 @@
+# -*- cmake -*-
+include(Prebuilt)
+include(GLIB)
+
+if (USESYSTEMLIBS)
+ include(FindPkgConfig)
+
+ pkg_check_modules(GSTREAMER10 REQUIRED gstreamer-1.0)
+ pkg_check_modules(GSTREAMER10_PLUGINS_BASE REQUIRED gstreamer-plugins-base-1.0)
+elseif (LINUX OR WINDOWS)
+ use_prebuilt_binary(gstreamer10)
+ use_prebuilt_binary(libxml2)
+ set(GSTREAMER10_FOUND ON FORCE BOOL)
+ set(GSTREAMER10_PLUGINS_BASE_FOUND ON FORCE BOOL)
+ set(GSTREAMER10_INCLUDE_DIRS
+ ${GLIB_INCLUDE_DIRS}
+ ${LIBS_PREBUILT_DIR}/include/gstreamer-1.0
+ ${LIBS_PREBUILT_DIR}/include/libxml2
+ )
+ # We don't need to explicitly link against gstreamer itself, because
+ # LLMediaImplGStreamer probes for the system's copy at runtime.
+ set(GSTREAMER10_LIBRARIES)
+endif (USESYSTEMLIBS)
+
+if (GSTREAMER10_FOUND AND GSTREAMER10_PLUGINS_BASE_FOUND)
+ set(GSTREAMER10 ON CACHE BOOL "Build with GStreamer-1.0 streaming media support.")
+endif (GSTREAMER10_FOUND AND GSTREAMER10_PLUGINS_BASE_FOUND)
+
+if (GSTREAMER10)
+ add_definitions(-DLL_GSTREAMER10_ENABLED=1)
+endif (GSTREAMER10)
+
diff --git a/indra/cmake/Hunspell.cmake b/indra/cmake/Hunspell.cmake
index 06227b3fe2..34e0fb3c35 100644
--- a/indra/cmake/Hunspell.cmake
+++ b/indra/cmake/Hunspell.cmake
@@ -13,7 +13,7 @@ else (USESYSTEMLIBS)
elseif(DARWIN)
set(HUNSPELL_LIBRARY hunspell-1.3)
elseif(LINUX)
- set(HUNSPELL_LIBRARY hunspell-1.3)
+ set(HUNSPELL_LIBRARY libhunspell-1.3.a)
else()
message(FATAL_ERROR "Invalid platform")
endif()
diff --git a/indra/cmake/MediaPluginBase.cmake b/indra/cmake/MediaPluginBase.cmake
index 2be035b641..17890c25fd 100644
--- a/indra/cmake/MediaPluginBase.cmake
+++ b/indra/cmake/MediaPluginBase.cmake
@@ -1,5 +1,26 @@
# -*- cmake -*-
+# Try to find pulse header, if we got them we can use the linux volume catcher
+if (LINUX)
+ include(GLIB)
+
+ include_directories( ${GLIB_INCLUDE_DIRS} )
+
+ foreach( PULSE_FILE pulse/introspect.h pulse/context.h pulse/subscribe.h pulse/glib-mainloop.h )
+ find_path( PULSE_FILE_${PULSE_FILE}_FOUND ${PULSE_FILE} NO_CACHE)
+ if( NOT PULSE_FILE_${PULSE_FILE}_FOUND )
+ message( "Looking for ${PULSE_FILE} ... not found")
+ message( FATAL_ERROR "Pulse header not found" )
+ else()
+ message( "Looking for ${PULSE_FILE} ... found")
+ endif()
+ endforeach()
+
+ message( "Building with linux volume catcher" )
+ set(LINUX_VOLUME_CATCHER linux_volume_catcher.cpp)
+
+endif()
+
set(MEDIA_PLUGIN_BASE_INCLUDE_DIRS
${LIBS_OPEN_DIR}/media_plugins/base/
diff --git a/indra/cmake/OPENAL.cmake b/indra/cmake/OPENAL.cmake
index 1bbfff6f98..fe52d1a9c9 100644
--- a/indra/cmake/OPENAL.cmake
+++ b/indra/cmake/OPENAL.cmake
@@ -3,12 +3,14 @@ include(Linking)
include(Prebuilt)
if (LINUX)
- set(OPENAL ON CACHE BOOL "Enable OpenAL")
+ use_prebuilt_binary(openal) #Always need the .so for voice
+ set(OPENAL OFF CACHE BOOL "Enable OpenAL")
else (LINUX)
set(OPENAL OFF CACHE BOOL "Enable OpenAL")
endif (LINUX)
if (OPENAL)
+ message( WARNING "Using OpenAL is discouraged due to no maintenance of the viewers openal integration, possible memory leaks and no support for streaming audio. Switch to fmodstudio if possible" )
set(OPENAL_LIB_INCLUDE_DIRS "${LIBS_PREBUILT_DIR}/include/AL")
if (USESYSTEMLIBS)
include(FindPkgConfig)
diff --git a/indra/cmake/OpenGL.cmake b/indra/cmake/OpenGL.cmake
index 3cb47a072c..c6ff24414b 100644
--- a/indra/cmake/OpenGL.cmake
+++ b/indra/cmake/OpenGL.cmake
@@ -16,3 +16,21 @@ endif (BUILD_HEADLESS)
include(FindOpenGL)
+if(LINUX)
+ if( NOT OPENGL_FOUND )
+ message( FATAL_ERROR "OpenGL not found, install mesa-common-dev libgl1-mesa-dev" )
+ endif()
+
+ find_file( GLUH "GL/glu.h" )
+ if( NOT GLUH )
+ message( FATAL_ERROR "GL/glu.h not found, install libglu1-mesa-dev" )
+ endif()
+ find_library( XINERAMA Xinerama )
+ if( NOT XINERAMA )
+ message( FATAL_ERROR "Cannot link with -lXinerame, install libxinerama-dev" )
+ endif()
+ find_library( XRANDR Xrandr)
+ if( NOT XRANDR )
+ message( FATAL_ERROR "Cannot link with -lXrandr, install libxrandr-dev" )
+ endif()
+endif()
diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake
index 6ac5cf3fc2..162eaf6a6c 100644
--- a/indra/cmake/Python.cmake
+++ b/indra/cmake/Python.cmake
@@ -14,50 +14,28 @@ if (WINDOWS)
)
else()
find_program(PYTHON_EXECUTABLE
- NAMES python25.exe python23.exe python.exe
+ NAMES python.exe
NO_DEFAULT_PATH # added so that cmake does not find cygwin python
PATHS
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.8\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath]
- [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.8\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath]
- [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\3.7\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\3.8\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\3.9\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\3.10\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\3.11\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\3.7\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\3.8\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\3.9\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\3.10\\InstallPath]
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\3.11\\InstallPath]
)
endif()
-elseif (EXISTS /etc/debian_version)
- # On Debian and Ubuntu, avoid Python 2.4 if possible.
-
- find_program(PYTHON_EXECUTABLE python PATHS /usr/bin)
+ include(FindPythonInterp)
+else()
+ find_program(PYTHON_EXECUTABLE python3)
if (PYTHON_EXECUTABLE)
set(PYTHONINTERP_FOUND ON)
endif (PYTHON_EXECUTABLE)
-elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
- # On MAC OS X be sure to search standard locations first
-
- string(REPLACE ":" ";" PATH_LIST "$ENV{PATH}")
- find_program(PYTHON_EXECUTABLE
- NAMES python python25 python24 python23
- NO_DEFAULT_PATH # Avoid searching non-standard locations first
- PATHS
- /bin
- /usr/bin
- /usr/local/bin
- ${PATH_LIST}
- )
-
- if (PYTHON_EXECUTABLE)
- set(PYTHONINTERP_FOUND ON)
- endif (PYTHON_EXECUTABLE)
-else (WINDOWS)
- include(FindPythonInterp)
endif (WINDOWS)
if (NOT PYTHON_EXECUTABLE)
diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake
index f1a8b68900..de567bdba0 100644
--- a/indra/cmake/UI.cmake
+++ b/indra/cmake/UI.cmake
@@ -1,27 +1,34 @@
# -*- cmake -*-
include(Prebuilt)
include(FreeType)
+include(GLIB)
if (USESYSTEMLIBS)
include(FindPkgConfig)
+ if( NOT GTK_VERSION )
+ set( GTK_VERSION 2.0 )
+ endif()
if (LINUX)
set(PKGCONFIG_PACKAGES
atk
cairo
- gdk-2.0
+ gdk-${GTK_VERSION}
gdk-pixbuf-2.0
glib-2.0
gmodule-2.0
- gtk+-2.0
+ gtk+-${GTK_VERSION}
gthread-2.0
libpng
pango
pangoft2
- pangox
- pangoxft
- sdl
+ sdl2
)
+ if( GTK_VERSION LESS "3.0" )
+ LIST( APPEND PKGCONFIG_PACKAGES pangoxft )
+ else()
+ add_definitions( -DGTK_DISABLE_DEPRECATED)
+ endif()
endif (LINUX)
foreach(pkg ${PKGCONFIG_PACKAGES})
@@ -31,29 +38,16 @@ if (USESYSTEMLIBS)
list(APPEND UI_LIBRARIES ${${pkg}_LIBRARIES})
add_definitions(${${pkg}_CFLAGS_OTHERS})
endforeach(pkg)
+ list(APPEND UI_LIBRARIES X11)
else (USESYSTEMLIBS)
if (LINUX)
- use_prebuilt_binary(gtk-atk-pango-glib)
+ use_prebuilt_binary(fltk)
endif (LINUX)
if (LINUX)
set(UI_LIB_NAMES
- freetype
- atk-1.0
- gdk-x11-2.0
- gdk_pixbuf-2.0
- glib-2.0
- gmodule-2.0
- gobject-2.0
- gthread-2.0
- gtk-x11-2.0
- pango-1.0
- pangoft2-1.0
- pangox-1.0
- #pangoxft-1.0
- gio-2.0
- pangocairo-1.0
- ffi
+ libfltk.a
+ libfreetype.a
)
foreach(libname ${UI_LIB_NAMES})
@@ -68,6 +62,7 @@ else (USESYSTEMLIBS)
endforeach(libname)
set(UI_LIBRARIES ${UI_LIBRARIES} Xinerama)
+ include_directories ( ${GLIB_INCLUDE_DIRS} )
endif (LINUX)
include_directories (
@@ -80,5 +75,5 @@ else (USESYSTEMLIBS)
endif (USESYSTEMLIBS)
if (LINUX)
- add_definitions(-DLL_GTK=1 -DLL_X11=1)
+ add_definitions(-DLL_X11=1 -DLL_FLTK=1)
endif (LINUX)
diff --git a/indra/cmake/bugsplat.cmake b/indra/cmake/bugsplat.cmake
index f709f35403..ce61b51b9b 100644
--- a/indra/cmake/bugsplat.cmake
+++ b/indra/cmake/bugsplat.cmake
@@ -12,17 +12,19 @@ endif (INSTALL_PROPRIETARY)
if (USE_BUGSPLAT)
if (NOT USESYSTEMLIBS)
include(Prebuilt)
- use_prebuilt_binary(bugsplat)
if (WINDOWS)
+ use_prebuilt_binary(bugsplat)
set(BUGSPLAT_LIBRARIES
${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib
)
elseif (DARWIN)
+ use_prebuilt_binary(bugsplat)
find_library(BUGSPLAT_LIBRARIES BugsplatMac REQUIRED
NO_DEFAULT_PATH PATHS "${ARCH_PREBUILT_DIRS_RELEASE}")
message("Bugsplat for OSX not fully implemented, please adapt llappdelegate-objc.mm to honor options of sending user name and settings.xml.")
else (WINDOWS)
- message(FATAL_ERROR "BugSplat is not supported; add -DUSE_BUGSPLAT=OFF")
+ use_prebuilt_binary(breakpad)
+ set(BUGSPLAT_LIBRARIES ${ARCH_PREBUILT_DIRS_RELEASE}/libbreakpad.a ${ARCH_PREBUILT_DIRS_RELEASE}/libbreakpad_client.a )
endif (WINDOWS)
else (NOT USESYSTEMLIBS)
set(BUGSPLAT_FIND_QUIETLY ON)
@@ -32,7 +34,14 @@ if (USE_BUGSPLAT)
set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name")
- set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/bugsplat)
+ if( LINUX )
+ set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/breakpad)
+ # Sadly we cannot have the nice things yet and need add_definitions for older cmake
+ #add_compile_definitions(__STDC_FORMAT_MACROS)
+ add_definitions(-D__STDC_FORMAT_MACROS)
+ else()
+ set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/bugsplat)
+ endif()
set(BUGSPLAT_DEFINE "LL_BUGSPLAT")
endif (USE_BUGSPLAT)
diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py
index dd4b9d2c1b..6d442496c5 100755
--- a/indra/cmake/run_build_test.py
+++ b/indra/cmake/run_build_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""\
@file run_build_test.py
@author Nat Goodspeed
@@ -17,7 +17,7 @@ line.
Example:
-python run_build_test.py -DFOO=bar myprog somearg otherarg
+python3 run_build_test.py -DFOO=bar myprog somearg otherarg
sets environment variable FOO=bar, then runs:
myprog somearg otherarg
@@ -47,7 +47,7 @@ $/LicenseInfo$
import os
import sys
import errno
-import HTMLParser
+import html.parser
import re
import signal
import subprocess
@@ -111,10 +111,10 @@ def main(command, arguments=[], libpath=[], vars={}):
# Now handle arbitrary environment variables. The tricky part is ensuring
# that all the keys and values we try to pass are actually strings.
if vars:
- for key, value in vars.items():
+ for key, value in list(vars.items()):
# As noted a few lines above, facilitate copy-paste rerunning.
log.info("%s='%s' \\" % (key, value))
- os.environ.update(dict([(str(key), str(value)) for key, value in vars.iteritems()]))
+ os.environ.update(dict([(str(key), str(value)) for key, value in vars.items()]))
# Run the child process.
command_list = [command]
command_list.extend(arguments)
@@ -194,7 +194,7 @@ def translate_rc(rc):
strc = str(rc)
return "terminated by signal %s" % strc
-class TableParser(HTMLParser.HTMLParser):
+class TableParser(html.parser.HTMLParser):
"""
This HTMLParser subclass is designed to parse the table we know exists
in windows-rcs.html, hopefully without building in too much knowledge of
@@ -204,9 +204,7 @@ class TableParser(HTMLParser.HTMLParser):
whitespace = re.compile(r'\s*$')
def __init__(self):
- # Because Python 2.x's HTMLParser is an old-style class, we must use
- # old-style syntax to forward the __init__() call -- not super().
- HTMLParser.HTMLParser.__init__(self)
+ super().__init__()
# this will collect all the data, eventually
self.table = []
# Stack whose top (last item) indicates where to append current
diff --git a/indra/copy_win_scripts/start-client.py b/indra/copy_win_scripts/start-client.py
index 2027ee6106..172cbe9bdd 100755
--- a/indra/copy_win_scripts/start-client.py
+++ b/indra/copy_win_scripts/start-client.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""\
@file start-client.py
@@ -28,12 +28,12 @@ import os
import llstart
def usage():
- print """start-client.py
+ print("""start-client.py
--grid
--farm
--region
- """
+ """)
def start_client(grid, slurl, build_config, my_args):
login_url = "https://login.%s.lindenlab.com/cgi-bin/login.cgi" % (grid)
@@ -42,7 +42,7 @@ def start_client(grid, slurl, build_config, my_args):
"--loginuri" : login_url }
viewer_args.update(my_args)
# *sigh* We must put --url at the end of the argument list.
- if viewer_args.has_key("--url"):
+ if "--url" in viewer_args:
slurl = viewer_args["--url"]
del(viewer_args["--url"])
viewer_args = llstart.get_args_from_dict(viewer_args)
@@ -54,7 +54,7 @@ def start_client(grid, slurl, build_config, my_args):
# but the exe is at indra/build-/newview/
build_path = os.path.dirname(os.getcwd());
f = open("start-client.log", "w")
- print >>f, "Viewer startup arguments:"
+ print("Viewer startup arguments:", file=f)
llstart.start("viewer", "../../newview",
"%s/newview/%s/firestorm-bin.exe" % (build_path, build_config),
viewer_args, f)
diff --git a/indra/doxygen/CMakeLists.txt b/indra/doxygen/CMakeLists.txt
index 84188bd32f..616b5cd09c 100644
--- a/indra/doxygen/CMakeLists.txt
+++ b/indra/doxygen/CMakeLists.txt
@@ -4,7 +4,7 @@
# other commands to guarantee full compatibility
# with the version specified
## prior to 2.8, the add_custom_target commands used in setting the version did not work correctly
-cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR)
set(ROOT_PROJECT_NAME "SecondLife" CACHE STRING
"The root project/makefile/solution name. Defaults to SecondLife.")
diff --git a/indra/fix-incredibuild.py b/indra/fix-incredibuild.py
index 171e4c7889..8da2a168a1 100755
--- a/indra/fix-incredibuild.py
+++ b/indra/fix-incredibuild.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
##
## $LicenseInfo:firstyear=2011&license=viewerlgpl$
## Second Life Viewer Source Code
@@ -27,7 +27,7 @@ import glob
def delete_file_types(path, filetypes):
if os.path.exists(path):
- print 'Cleaning: ' + path
+ print('Cleaning: ' + path)
orig_dir = os.getcwd();
os.chdir(path)
filelist = []
diff --git a/indra/lib/python/indra/ipc/llmessage.py b/indra/lib/python/indra/ipc/llmessage.py
index 91fb36b72c..663e2d9c63 100755
--- a/indra/lib/python/indra/ipc/llmessage.py
+++ b/indra/lib/python/indra/ipc/llmessage.py
@@ -26,8 +26,8 @@ THE SOFTWARE.
$/LicenseInfo$
"""
-from compatibility import Incompatible, Older, Newer, Same
-from tokenstream import TokenStream
+from .compatibility import Incompatible, Older, Newer, Same
+from .tokenstream import TokenStream
###
### Message Template
@@ -42,8 +42,8 @@ class Template:
def compatibleWithBase(self, base):
messagenames = (
- frozenset(self.messages.keys())
- | frozenset(base.messages.keys())
+ frozenset(list(self.messages.keys()))
+ | frozenset(list(base.messages.keys()))
)
compatibility = Same()
@@ -142,7 +142,7 @@ class Message:
baselen = len(base.blocks)
samelen = min(selflen, baselen)
- for i in xrange(0, samelen):
+ for i in range(0, samelen):
selfblock = self.blocks[i]
baseblock = base.blocks[i]
@@ -196,7 +196,7 @@ class Block(object):
selflen = len(self.variables)
baselen = len(base.variables)
- for i in xrange(0, min(selflen, baselen)):
+ for i in range(0, min(selflen, baselen)):
selfvar = self.variables[i]
basevar = base.variables[i]
diff --git a/indra/lib/python/indra/ipc/tokenstream.py b/indra/lib/python/indra/ipc/tokenstream.py
index b96f26d3ff..ab97e94846 100755
--- a/indra/lib/python/indra/ipc/tokenstream.py
+++ b/indra/lib/python/indra/ipc/tokenstream.py
@@ -60,7 +60,7 @@ class ParseError(Exception):
return "line %d: %s @ ... %s" % (
self.line, self.reason, self._contextString())
- def __nonzero__(self):
+ def __bool__(self):
return False
diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py
index dd331a4556..5f60c4c7fd 100755
--- a/indra/lib/python/indra/util/llmanifest.py
+++ b/indra/lib/python/indra/util/llmanifest.py
@@ -28,7 +28,7 @@ $/LicenseInfo$
"""
from collections import namedtuple, defaultdict
-import commands
+import subprocess
import errno
import filecmp
import fnmatch
@@ -85,6 +85,7 @@ def proper_windows_path(path, current_platform = sys.platform):
def get_default_platform(dummy):
return {'linux2':'linux',
'linux1':'linux',
+ 'linux':'linux',
'cygwin':'windows',
'win32':'windows',
'darwin':'darwin'
@@ -164,20 +165,20 @@ BASE_ARGUMENTS=[
def usage(arguments, srctree=""):
nd = {'name':sys.argv[0]}
- print """Usage:
+ print("""Usage:
%(name)s [options] [destdir]
Options:
- """ % nd
+ """ % nd)
for arg in arguments:
default = arg['default']
if hasattr(default, '__call__'):
default = "(computed value) \"" + str(default(srctree)) + '"'
elif default is not None:
default = '"' + default + '"'
- print "\t--%s Default: %s\n\t%s\n" % (
+ print("\t--%s Default: %s\n\t%s\n" % (
arg['name'],
default,
- arg['description'] % nd)
+ arg['description'] % nd))
def main(extra=[]):
## print ' '.join((("'%s'" % item) if ' ' in item else item)
@@ -202,10 +203,10 @@ def main(extra=[]):
for k in 'artwork build dest source'.split():
args[k] = os.path.normpath(args[k])
- print "Source tree:", args['source']
- print "Artwork tree:", args['artwork']
- print "Build tree:", args['build']
- print "Destination tree:", args['dest']
+ print("Source tree:", args['source'])
+ print("Artwork tree:", args['artwork'])
+ print("Build tree:", args['build'])
+ print("Destination tree:", args['dest'])
# early out for help
if 'help' in args:
@@ -228,7 +229,7 @@ def main(extra=[]):
vf = open(args['versionfile'], 'r')
args['version'] = vf.read().strip().split('.')
except:
- print "Unable to read versionfile '%s'" % args['versionfile']
+ print("Unable to read versionfile '%s'" % args['versionfile'])
# This will break copy_w_viewer_manifest on Windows 32 and 64 bit builds, the versionfile will not create until the firestorm project.
# As copy_w_viewer_manifest does not seem to need the version attribute, we supress the exception for now.
# raise
@@ -242,7 +243,7 @@ def main(extra=[]):
# debugging
for opt in args:
- print "Option:", opt, "=", args[opt]
+ print("Option:", opt, "=", args[opt])
# pass in sourceid as an argument now instead of an environment variable
args['sourceid'] = os.environ.get("sourceid", "")
@@ -250,18 +251,18 @@ def main(extra=[]):
# Build base package.
touch = args.get('touch')
if touch:
- print '================ Creating base package'
+ print('================ Creating base package')
else:
- print '================ Starting base copy'
+ print('================ Starting base copy')
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
wm.do(*args['actions'])
# Store package file for later if making touched file.
base_package_file = ""
if touch:
- print '================ Created base package ', wm.package_file
+ print('================ Created base package ', wm.package_file)
base_package_file = "" + wm.package_file
else:
- print '================ Finished base copy'
+ print('================ Finished base copy')
# handle multiple packages if set
# ''.split() produces empty list
@@ -288,26 +289,26 @@ def main(extra=[]):
args['sourceid'] = os.environ.get(package_id + "_sourceid")
args['dest'] = base_dest_template.format(package_id)
if touch:
- print '================ Creating additional package for "', package_id, '" in ', args['dest']
+ print('================ Creating additional package for "', package_id, '" in ', args['dest'])
else:
- print '================ Starting additional copy for "', package_id, '" in ', args['dest']
+ print('================ Starting additional copy for "', package_id, '" in ', args['dest'])
try:
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
wm.do(*args['actions'])
except Exception as err:
sys.exit(str(err))
if touch:
- print '================ Created additional package ', wm.package_file, ' for ', package_id
+ print('================ Created additional package ', wm.package_file, ' for ', package_id)
with open(base_touch_template.format(package_id), 'w') as fp:
fp.write('set package_file=%s\n' % wm.package_file)
else:
- print '================ Finished additional copy "', package_id, '" in ', args['dest']
+ print('================ Finished additional copy "', package_id, '" in ', args['dest'])
# Write out the package file in this format, so that it can easily be called
# and used in a .bat file - yeah, it sucks, but this is the simplest...
if touch:
with open(touch, 'w') as fp:
fp.write('set package_file=%s\n' % base_package_file)
- print 'touched', touch
+ print('touched', touch)
return 0
class LLManifestRegistry(type):
@@ -319,8 +320,7 @@ class LLManifestRegistry(type):
MissingFile = namedtuple("MissingFile", ("pattern", "tried"))
-class LLManifest(object):
- __metaclass__ = LLManifestRegistry
+class LLManifest(object, metaclass=LLManifestRegistry):
manifests = {}
def for_platform(self, platform, arch = None):
if arch:
@@ -412,8 +412,8 @@ class LLManifest(object):
def display_stacks(self):
width = 1 + max(len(stack) for stack in self.PrefixManager.stacks)
for stack in self.PrefixManager.stacks:
- print "{} {}".format((stack + ':').ljust(width),
- os.path.join(*getattr(self, stack)))
+ print("{} {}".format((stack + ':').ljust(width),
+ os.path.join(*getattr(self, stack))))
class PrefixManager(object):
# stack attributes we manage in this LLManifest (sub)class
@@ -430,7 +430,7 @@ class LLManifest(object):
self.prevlen = { stack: len(getattr(self.manifest, stack)) - 1
for stack in self.stacks }
- def __nonzero__(self):
+ def __bool__(self):
# If the caller wrote:
# if self.prefix(...):
# then a value of this class had better evaluate as 'True'.
@@ -456,7 +456,7 @@ class LLManifest(object):
# if we restore the length of each stack to what it was before the
# current prefix() block, it doesn't matter whether end_prefix()
# was called or not.
- for stack, prevlen in self.prevlen.items():
+ for stack, prevlen in list(self.prevlen.items()):
# find the attribute in 'self.manifest' named by 'stack', and
# truncate that list back to 'prevlen'
del getattr(self.manifest, stack)[prevlen:]
@@ -475,7 +475,7 @@ class LLManifest(object):
build = self.build_prefix.pop()
dst = self.dst_prefix.pop()
if descr and not(src == descr or build == descr or dst == descr):
- raise ValueError, "End prefix '" + descr + "' didn't match '" +src+ "' or '" +dst + "'"
+ raise ValueError("End prefix '" + descr + "' didn't match '" +src+ "' or '" +dst + "'")
def get_src_prefix(self):
""" Returns the current source prefix."""
@@ -542,7 +542,7 @@ class LLManifest(object):
Runs an external command.
Raises ManifestError exception if the command returns a nonzero status.
"""
- print "Running command:", command
+ print("Running command:", command)
sys.stdout.flush()
try:
subprocess.check_call(command)
@@ -556,7 +556,7 @@ class LLManifest(object):
Runs an external command.
Raises ManifestError exception if the command returns a nonzero status.
"""
- print "Running command:", command
+ print("Running command:", command)
sys.stdout.flush()
try:
subprocess.check_call(command, shell=True)
@@ -570,18 +570,15 @@ class LLManifest(object):
a) verify that you really have created it
b) schedule it for cleanup"""
if not os.path.exists(path):
- raise ManifestError, "Should be something at path " + path
+ raise ManifestError("Should be something at path " + path)
self.created_paths.append(path)
def put_in_file(self, contents, dst, src=None):
# write contents as dst
dst_path = self.dst_path_of(dst)
self.cmakedirs(os.path.dirname(dst_path))
- f = open(dst_path, "wb")
- try:
+ with open(dst_path, 'wb') as f:
f.write(contents)
- finally:
- f.close()
# Why would we create a file in the destination tree if not to include
# it in the installer? The default src=None (plus the fact that the
@@ -594,13 +591,12 @@ class LLManifest(object):
if dst == None:
dst = src
# read src
- f = open(self.src_path_of(src), "rbU")
- contents = f.read()
- f.close()
+ with open(self.src_path_of(src), "r") as f:
+ contents = f.read()
# apply dict replacements
- for old, new in searchdict.iteritems():
+ for old, new in searchdict.items():
contents = contents.replace(old, new)
- self.put_in_file(contents, dst)
+ self.put_in_file(contents.encode(), dst)
self.created_paths.append(dst)
def copy_action(self, src, dst):
@@ -610,7 +606,7 @@ class LLManifest(object):
self.created_paths.append(dst)
self.ccopymumble(src, dst)
else:
- print "Doesn't exist:", src
+ print("Doesn't exist:", src)
def package_action(self, src, dst):
pass
@@ -628,8 +624,8 @@ class LLManifest(object):
# file error until all were resolved. This way permits the developer
# to resolve them all at once.
if self.missing:
- print '*' * 72
- print "Missing files:"
+ print('*' * 72)
+ print("Missing files:")
# Instead of just dumping each missing file and all the places we
# looked for it, group by common sets of places we looked. Use a
# set to store the 'tried' directories, to avoid mismatches due to
@@ -640,13 +636,13 @@ class LLManifest(object):
organize[frozenset(missingfile.tried)].add(missingfile.pattern)
# Now dump all the patterns sought in each group of 'tried'
# directories.
- for tried, patterns in organize.items():
- print " Could not find in:"
+ for tried, patterns in list(organize.items()):
+ print(" Could not find in:")
for dir in sorted(tried):
- print " %s" % dir
+ print(" %s" % dir)
for pattern in sorted(patterns):
- print " %s" % pattern
- print '*' * 72
+ print(" %s" % pattern)
+ print('*' * 72)
raise MissingError('%s patterns could not be found' % len(self.missing))
def copy_finish(self):
@@ -659,7 +655,7 @@ class LLManifest(object):
unpacked_file_name = "unpacked_%(plat)s_%(vers)s.tar" % {
'plat':self.args['platform'],
'vers':'_'.join(self.args['version'])}
- print "Creating unpacked file:", unpacked_file_name
+ print("Creating unpacked file:", unpacked_file_name)
# could add a gz here but that doubles the time it takes to do this step
tf = tarfile.open(self.src_path_of(unpacked_file_name), 'w:')
# add the entire installation package, at the very top level
@@ -670,7 +666,7 @@ class LLManifest(object):
""" Delete paths that were specified to have been created by this script"""
for c in self.created_paths:
# *TODO is this gonna be useful?
- print "Cleaning up " + c
+ print("Cleaning up " + c)
def process_either(self, src, dst):
# If it's a real directory, recurse through it --
@@ -719,7 +715,7 @@ class LLManifest(object):
def remove(self, *paths):
for path in paths:
if os.path.exists(path):
- print "Removing path", path
+ print("Removing path", path)
if os.path.isdir(path):
shutil.rmtree(path)
else:
@@ -781,7 +777,7 @@ class LLManifest(object):
except (IOError, os.error) as why:
errors.append((srcname, dstname, why))
if errors:
- raise ManifestError, errors
+ raise ManifestError(errors)
def cmakedirs(self, path):
@@ -893,13 +889,13 @@ class LLManifest(object):
break
else:
# no more prefixes left to try
- print("\nunable to find '%s'; looked in:\n %s" % (src, '\n '.join(try_prefixes)))
+ print(("\nunable to find '%s'; looked in:\n %s" % (src, '\n '.join(try_prefixes))))
self.missing.append(MissingFile(pattern=src, tried=try_prefixes))
# At this point 'count' might never have been successfully
# assigned! Even if it was, though, we can be sure it is 0.
return 0
- print "%d files" % count
+ print("%d files" % count)
# Let caller check whether we processed as many files as expected. In
# particular, let caller notice 0.
diff --git a/indra/lib/python/indra/util/test_win32_manifest.py b/indra/lib/python/indra/util/test_win32_manifest.py
index e7ba607be4..367e787546 100755
--- a/indra/lib/python/indra/util/test_win32_manifest.py
+++ b/indra/lib/python/indra/util/test_win32_manifest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""\
@file test_win32_manifest.py
@brief Test an assembly binding version and uniqueness in a windows dll or exe.
@@ -44,10 +44,10 @@ class NoMatchingAssemblyException(AssemblyTestException):
pass
def get_HKLM_registry_value(key_str, value_str):
- import _winreg
- reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
- key = _winreg.OpenKey(reg, key_str)
- value = _winreg.QueryValueEx(key, value_str)[0]
+ import winreg
+ reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
+ key = winreg.OpenKey(reg, key_str)
+ value = winreg.QueryValueEx(key, value_str)[0]
#print 'Found: %s' % value
return value
@@ -64,12 +64,12 @@ def find_vc_dir():
(product, version))
try:
return get_HKLM_registry_value(key_str, value_str)
- except WindowsError, err:
+ except WindowsError as err:
x64_key_str = (r'SOFTWARE\Wow6432Node\Microsoft\%s\%s\Setup\VC' % (product, version))
try:
return get_HKLM_registry_value(x64_key_str, value_str)
except:
- print >> sys.stderr, "Didn't find MS %s version %s " % (product,version)
+ print("Didn't find MS %s version %s " % (product,version), file=sys.stderr)
raise
@@ -79,7 +79,7 @@ def find_mt_path():
return mt_path
def test_assembly_binding(src_filename, assembly_name, assembly_ver):
- print "checking %s dependency %s..." % (src_filename, assembly_name)
+ print("checking %s dependency %s..." % (src_filename, assembly_name))
(tmp_file_fd, tmp_file_name) = tempfile.mkstemp(suffix='.xml')
tmp_file = os.fdopen(tmp_file_fd)
@@ -90,10 +90,10 @@ def test_assembly_binding(src_filename, assembly_name, assembly_ver):
if os.path.splitext(src_filename)[1].lower() == ".dll":
resource_id = ";#2"
system_call = '%s -nologo -inputresource:%s%s -out:%s > NUL' % (mt_path, src_filename, resource_id, tmp_file_name)
- print "Executing: %s" % system_call
+ print("Executing: %s" % system_call)
mt_result = os.system(system_call)
if mt_result == 31:
- print "No manifest found in %s" % src_filename
+ print("No manifest found in %s" % src_filename)
raise NoManifestException()
manifest_dom = parse(tmp_file_name)
@@ -105,30 +105,30 @@ def test_assembly_binding(src_filename, assembly_name, assembly_ver):
versions.append(node.getAttribute('version'))
if len(versions) == 0:
- print "No matching assemblies found in %s" % src_filename
+ print("No matching assemblies found in %s" % src_filename)
raise NoMatchingAssemblyException()
#elif len(versions) > 1:
- # print "Multiple bindings to %s found:" % assembly_name
- # print versions
- # print
+ # print("Multiple bindings to %s found:" % assembly_name)
+ # print(versions)
+ # print()
# raise MultipleBindingsException(versions)
#elif versions[0] != assembly_ver:
- # print "Unexpected version found for %s:" % assembly_name
- # print "Wanted %s, found %s" % (assembly_ver, versions[0])
- # print
+ # print("Unexpected version found for %s:" % assembly_name)
+ # print("Wanted %s, found %s" % (assembly_ver, versions[0]))
+ # print()
# raise UnexpectedVersionException(assembly_ver, versions[0])
os.remove(tmp_file_name)
- print "SUCCESS: %s OK!" % src_filename
- print
+ print("SUCCESS: %s OK!" % src_filename)
+ print()
if __name__ == '__main__':
- print
- print "Running test_win32_manifest.py..."
+ print()
+ print("Running test_win32_manifest.py...")
usage = 'test_win32_manfest '
@@ -137,9 +137,9 @@ if __name__ == '__main__':
assembly_name = sys.argv[2]
assembly_ver = sys.argv[3]
except:
- print "Usage:"
- print usage
- print
+ print("Usage:")
+ print(usage)
+ print()
raise
test_assembly_binding(src_filename, assembly_name, assembly_ver)
diff --git a/indra/linux_crash_logger/CMakeLists.txt b/indra/linux_crash_logger/CMakeLists.txt
index aa82ed12cc..ab8ef14fce 100644
--- a/indra/linux_crash_logger/CMakeLists.txt
+++ b/indra/linux_crash_logger/CMakeLists.txt
@@ -3,18 +3,11 @@
project(linux_crash_logger)
include(00-Common)
-include(GLH)
-include(LLCoreHttp)
-include(LLCommon)
-include(LLCrashLogger)
-include(LLMath)
-include(LLMessage)
-include(LLFileSystem)
-include(LLXML)
include(Linking)
include(UI)
-include(FreeType)
-include(Boost)
+include(CURL)
+include(OpenSSL)
+include(ZLIB)
include_directories(
${LLCOREHTTP_INCLUDE_DIRS}
@@ -36,7 +29,6 @@ include_directories(SYSTEM
set(linux_crash_logger_SOURCE_FILES
linux_crash_logger.cpp
- llcrashloggerlinux.cpp
)
set(linux_crash_logger_HEADER_FILES
@@ -61,19 +53,13 @@ set(LIBRT_LIBRARY rt)
target_link_libraries(linux-crash-logger
- ${LLCRASHLOGGER_LIBRARIES}
- ${LLFILESYSTEM_LIBRARIES}
- ${LLXML_LIBRARIES}
- ${LLMESSAGE_LIBRARIES}
- ${LLMATH_LIBRARIES}
- ${LLCOREHTTP_LIBRARIES}
- ${LLCOMMON_LIBRARIES}
- ${BOOST_FIBER_LIBRARY}
- ${BOOST_CONTEXT_LIBRARY}
${UI_LIBRARIES}
- ${DB_LIBRARIES}
- ${FREETYPE_LIBRARIES}
+ ${CURL_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ ${CRYPTO_LIBRARIES}
+ ${ZLIB_LIBRARIES}
${LIBRT_LIBRARY}
+ X11
)
add_custom_target(linux-crash-logger-target ALL
diff --git a/indra/linux_crash_logger/linux_crash_logger.cpp b/indra/linux_crash_logger/linux_crash_logger.cpp
index 63e5409876..5d55e551a4 100644
--- a/indra/linux_crash_logger/linux_crash_logger.cpp
+++ b/indra/linux_crash_logger/linux_crash_logger.cpp
@@ -24,35 +24,77 @@
* $/LicenseInfo$
*/
-#include "linden_common.h"
-#include "llcrashloggerlinux.h"
-#include "llsdutil.h"
+#include
+#include
+#include
+#include
+/* Called via
+ execl( gCrashLogger.c_str(), gCrashLogger.c_str(), descriptor.path(), gVersion.c_str(), gBugsplatDB.c_str(), nullptr );
+*/
int main(int argc, char **argv)
{
- LL_INFOS() << "Starting crash reporter." << LL_ENDL;
+ std::cerr << "linux crash logger called: ";
+ for( int i = 1; i < argc; ++i )
+ std::cerr << argv[i] << " ";
- LLCrashLoggerLinux app;
- app.parseCommandOptions(argc, argv);
+ std::cerr << std::endl;
- LLSD options = LLApp::instance()->getOptionData(
- LLApp::PRIORITY_COMMAND_LINE);
- //LLApp::PRIORITY_RUNTIME_OVERRIDE);
-
-
- if (!(options.has("pid") && options.has("dumpdir")))
+ if( argc < 4 )
{
- LL_WARNS() << "Insufficient parameters to crash report." << LL_ENDL;
+ std::cerr << argv[0] << "Not enough arguments" << std::endl;
+ return 1;
}
- if (! app.init())
+ std::string dmpFile{ argv[1] };
+ std::string version{ argv[2] };
+ std::string strDb{ argv[3] };
+ std::string strAsk{ argv[4] };
+
+ if( strAsk == "ask" )
{
- LL_WARNS() << "Unable to initialize application." << LL_ENDL;
- return 1;
+ auto choice = fl_choice( "Firestorm has crashed, submit the minidump?", "No", "Yes", nullptr );
+ if( choice == 0 )
+ {
+ std::cerr << "Abort send due to users choice" << std::endl;
+ return 0;
+ }
}
- app.frame();
- app.cleanup();
- LL_INFOS() << "Crash reporter finished normally." << LL_ENDL;
- return 0;
+ std::string url{ "https://" };
+ url += strDb;
+ url += ".bugsplat.com/post/bp/crash/crashpad.php";
+
+ curl_global_init(CURL_GLOBAL_ALL);
+
+ auto curl = curl_easy_init();
+ if( curl)
+ {
+ auto form = curl_mime_init(curl);
+
+ auto field = curl_mime_addpart(form);
+ curl_mime_name(field, "upload_file_minidump");
+ curl_mime_filedata(field, dmpFile.c_str() );
+
+ field = curl_mime_addpart(form);
+ curl_mime_name(field, "product");
+ curl_mime_data(field, "Firestorm-Releasex64", CURL_ZERO_TERMINATED);
+
+ field = curl_mime_addpart(form);
+ curl_mime_name(field, "version");
+ curl_mime_data(field, version.c_str(), CURL_ZERO_TERMINATED);
+
+ curl_easy_setopt(curl, CURLOPT_URL, url.c_str() );
+ curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
+
+ auto res = curl_easy_perform(curl);
+
+ if(res != CURLE_OK)
+ std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
+
+ curl_easy_cleanup(curl);
+
+ curl_mime_free(form);
+ }
+ return 0;
}
diff --git a/indra/linux_crash_logger/llcrashloggerlinux.cpp b/indra/linux_crash_logger/llcrashloggerlinux.cpp
deleted file mode 100644
index f6fd71e849..0000000000
--- a/indra/linux_crash_logger/llcrashloggerlinux.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- * @file llcrashloggerlinux.cpp
- * @brief Linux crash logger implementation
- *
- * $LicenseInfo:firstyear=2003&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llcrashloggerlinux.h"
-
-#include
-
-#include "linden_common.h"
-
-#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
-#include "llerror.h"
-#include "llfile.h"
-#include "lltimer.h"
-#include "llstring.h"
-#include "lldir.h"
-#include "llsdserialize.h"
-
-#if LL_GTK
-# include "gtk/gtk.h"
-#endif // LL_GTK
-
-#define MAX_LOADSTRING 100
-
-// Fire-901 / Crashreporting: Brand for FS, add URL to privacy policy
-
-// These need to be localized.
-// static const char dialog_text[] =
-// "Second Life appears to have crashed or frozen last time it ran.\n"
-// "This crash reporter collects information about your computer's hardware, operating system, and some Second Life logs, all of which are used for debugging purposes only.\n"
-// "\n"
-// "Send crash report?";
-//
-// static const char dialog_title[] =
-// "Second Life Crash Logger";
-
-static const char dialog_text[] =
-"Firestorm appears to have crashed or frozen last time it ran.\n"
-"This crash reporter collects information about your computer's hardware, operating system which are used for debugging purposes only. SecondLife logs are not collected.\n"
-"This report will be send to firestormviewer.org. Review our privacy policy at http://www.firestormviewer.org/privacy-policy for more information.\n"
-"\n"
-"Send crash report?";
-
-static const char dialog_title[] =
-"Firestorm Crash Logger";
-
-//
-
-#if 0
-
-#if LL_GTK
-static void response_callback (GtkDialog *dialog,
- gint arg1,
- gpointer user_data)
-{
- gint *response = (gint*)user_data;
- *response = arg1;
- gtk_widget_destroy(GTK_WIDGET(dialog));
- gtk_main_quit();
-}
-#endif // LL_GTK
-
-static BOOL do_ask_dialog(void)
-{
-#if LL_GTK
- gtk_disable_setlocale();
- if (!gtk_init_check(NULL, NULL)) {
- LL_INFOS() << "Could not initialize GTK for 'ask to send crash report' dialog; not sending report." << LL_ENDL;
- return FALSE;
- }
-
- GtkWidget *win = NULL;
- GtkDialogFlags flags = GTK_DIALOG_MODAL;
- GtkMessageType messagetype = GTK_MESSAGE_QUESTION;
- GtkButtonsType buttons = GTK_BUTTONS_YES_NO;
- gint response = GTK_RESPONSE_NONE;
-
- win = gtk_message_dialog_new(NULL,
- flags, messagetype, buttons,
- "%s", dialog_text);
- gtk_window_set_type_hint(GTK_WINDOW(win),
- GDK_WINDOW_TYPE_HINT_DIALOG);
- gtk_window_set_title(GTK_WINDOW(win), dialog_title);
- g_signal_connect (win,
- "response",
- G_CALLBACK (response_callback),
- &response);
- gtk_widget_show_all (win);
- gtk_main();
-
- return (GTK_RESPONSE_OK == response ||
- GTK_RESPONSE_YES == response ||
- GTK_RESPONSE_APPLY == response);
-#else
- return FALSE;
-#endif // LL_GTK
-}
-#endif
-
-LLCrashLoggerLinux::LLCrashLoggerLinux(void)
-{
-}
-
-LLCrashLoggerLinux::~LLCrashLoggerLinux(void)
-{
-}
-
-void LLCrashLoggerLinux::gatherPlatformSpecificFiles()
-{
-}
-
-bool LLCrashLoggerLinux::frame()
-{
- // Get around the crash logger popping up all the time.
- // Right now there seems to be no easy way to test if there's logs from a real crash to send. Which
- // would be preferred, as then asking for sending in data makes sense. Right now the dialog will just open always.
-
- // bool send_logs = true;
- // if(CRASH_BEHAVIOR_ASK == getCrashBehavior())
- // {
- // send_logs = do_ask_dialog();
- // }
- // else if(CRASH_BEHAVIOR_NEVER_SEND == getCrashBehavior())
- // {
- // send_logs = false;
- // }
-
- bool send_logs = (CRASH_BEHAVIOR_NEVER_SEND == getCrashBehavior());
-
- //
-
- if(send_logs)
- {
- sendCrashLogs();
- }
- return true;
-}
-
-bool LLCrashLoggerLinux::cleanup()
-{
- commonCleanup();
- mKeyMaster.releaseMaster();
- return true;
-}
-
-void LLCrashLoggerLinux::updateApplication(const std::string& message)
-{
- LLCrashLogger::updateApplication(message);
-}
diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt
index 92a5cfe22f..804b36b226 100644
--- a/indra/llaudio/CMakeLists.txt
+++ b/indra/llaudio/CMakeLists.txt
@@ -11,7 +11,7 @@ include(LLMath)
include(LLMessage)
include(LLFileSystem)
-include_directories(
+include_directories( SYSTEM
${LLAUDIO_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 02b1d38fa9..0ec4898b77 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -13,7 +13,7 @@ include(Copy3rdPartyLibs)
include(ZLIB)
include(URIPARSER)
-include_directories(
+include_directories( SYSTEM
${EXPAT_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${JSONCPP_INCLUDE_DIR}
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 41c4e5d97c..420c7c26c8 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -544,8 +544,6 @@ namespace
protected:
Globals();
public:
- std::ostringstream messageStream;
- bool messageStreamInUse;
std::string mFatalMessage;
void addCallSite(LLError::CallSite&);
@@ -562,7 +560,9 @@ namespace
};
Globals::Globals()
- : mSettingsConfig(new SettingsConfig())
+ :
+ callSites(),
+ mSettingsConfig(new SettingsConfig())
{
}
@@ -1449,7 +1449,10 @@ namespace LLError
if (site.mLevel == LEVEL_ERROR)
{
g->mFatalMessage = message;
- s->mCrashFunction(message);
+ if (s->mCrashFunction)
+ {
+ s->mCrashFunction(message);
+ }
}
}
}
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 3a58c029b0..d4c4d29f50 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -80,7 +80,7 @@ const int LL_ERR_NOERR = 0;
#endif // !_DEBUG
-#define llassert_always_msg(func, msg) if (LL_UNLIKELY(!(func))) LL_ERRS() << "ASSERT (" << msg << ")" << LL_ENDL
+#define llassert_always_msg(func, msg) if (LL_UNLIKELY(!(func))) { LL_ERRS() << "ASSERT (" << msg << ")" << LL_ENDL; /* call abort, this will not be reached but signaled GCC after this line the program exists*/ std::abort(); }
#define llassert_always(func) llassert_always_msg(func, #func)
diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index e8ea0ab398..2704f8b6de 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -86,7 +86,7 @@ public:
// notice Python specially: we provide Python LLSD serialization
// support, so there's a pretty good reason to implement plugins
// in that language.
- if (cparams.args.size() && (desclower == "python" || desclower == "python.exe"))
+ if (cparams.args.size() && (desclower == "python" || desclower == "python3" || desclower == "python.exe"))
{
mDesc = LLProcess::basename(cparams.args()[0]);
}
diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp
index f8a93baf45..100eb57555 100644
--- a/indra/llcommon/llmetricperformancetester.cpp
+++ b/indra/llcommon/llmetricperformancetester.cpp
@@ -189,7 +189,6 @@ LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic()
void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd)
{
incrementCurrentCount() ;
- (*sd)[getCurrentLabelName()]["Name"] = mName ;
}
void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd)
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index d5cc14ff55..a1ee1cb7ba 100644
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -47,6 +47,12 @@
#include
#include
+// Suppress warnings about the string fiddling
+#if LL_LINUX
+#pragma GCC diagnostic ignored "-Wstringop-truncation"
+#endif
+//
+
// U32
LLSD ll_sd_from_U32(const U32 val)
{
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index c9f17e29b8..2dc18a39e1 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -107,7 +107,7 @@ LLOSInfo::LLOSInfo() :
#if LL_WINDOWS
- if (IsWindows10OrGreater())
+ if (IsWindows10OrGreater())
{
mMajorVer = 10;
mMinorVer = 0;
@@ -248,13 +248,24 @@ LLOSInfo::LLOSInfo() :
}
}
- // Windows 11 detection
- if (mBuild >= 22000)
- {
- mMajorVer = 11;
- LLStringUtil::replaceString(mOSStringSimple, "10", "11");
- }
- //
+ if (mBuild >= 22000)
+ {
+ // At release Windows 11 version was 10.0.22000.194
+ // Windows 10 version was 10.0.19043.1266
+ // There is no warranty that Win10 build won't increase,
+ // so until better solution is found or Microsoft updates
+ // SDK with IsWindows11OrGreater(), indicate "10/11"
+ //
+ // Current alternatives:
+ // Query WMI's Win32_OperatingSystem for OS string. Slow
+ // and likely to return 'compatibility' string.
+ // Check presence of dlls/libs or may be their version.
+ // Windows 11 detection
+ //mOSStringSimple = "Microsoft Windows 10/11";
+ mMajorVer = 11;
+ LLStringUtil::replaceString(mOSStringSimple, "10", "11");
+ //
+ }
}
mOSString = mOSStringSimple;
@@ -1262,18 +1273,12 @@ BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile)
LLFILE *dst = NULL;
S32 bytes = 0;
tmpfile = dstfile + ".t";
-
- // Proper UTF8->UTF16 handling for Windows
- // src = gzopen(srcfile.c_str(), "rb");
-#if LL_WINDOWS
- std::string utf8filename = srcfile;
- llutf16string utf16filename = utf8str_to_utf16str(utf8filename);
- src = gzopen_w(utf16filename.c_str(), "rb");
+#ifdef LL_WINDOWS
+ llutf16string utf16filename = utf8str_to_utf16str(srcfile);
+ src = gzopen_w(utf16filename.c_str(), "rb");
#else
- src = gzopen(srcfile.c_str(), "rb");/* Flawfinder: ignore */
+ src = gzopen(srcfile.c_str(), "rb");
#endif
- //
-
if (! src) goto err;
dst = LLFile::fopen(tmpfile, "wb"); /* Flawfinder: ignore */
if (! dst) goto err;
@@ -1308,17 +1313,13 @@ BOOL gzip_file(const std::string& srcfile, const std::string& dstfile)
S32 bytes = 0;
tmpfile = dstfile + ".t";
- // Proper UTF8->UTF16 handling for Windows
- // dst = gzopen(tmpfile.c_str(), "wb"); /* Flawfinder: ignore */
-#if LL_WINDOWS
- std::string utf8filename = tmpfile;
- llutf16string utf16filename = utf8str_to_utf16str(utf8filename);
- dst = gzopen_w(utf16filename.c_str(), "wb");
+#ifdef LL_WINDOWS
+ llutf16string utf16filename = utf8str_to_utf16str(tmpfile);
+ dst = gzopen_w(utf16filename.c_str(), "wb");
#else
- dst = gzopen(tmpfile.c_str(), "wb");/* Flawfinder: ignore */
+ dst = gzopen(tmpfile.c_str(), "wb");
#endif
- //
-
+
if (! dst) goto err;
src = LLFile::fopen(srcfile, "rb"); /* Flawfinder: ignore */
if (! src) goto err;
diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp
index 9d71e327d8..9754353ab0 100644
--- a/indra/llcommon/tests/llleap_test.cpp
+++ b/indra/llcommon/tests/llleap_test.cpp
@@ -145,13 +145,13 @@ namespace tut
" data = ''.join(parts)\n"
" assert len(data) == length\n"
" try:\n"
- " return llsd.parse(data)\n"
+ " return llsd.parse(data.encode())\n"
// Seems the old indra.base.llsd module didn't properly
// convert IndexError (from running off end of string) to
// LLSDParseError.
- " except (IndexError, llsd.LLSDParseError), e:\n"
+ " except (IndexError, llsd.LLSDParseError) as e:\n"
" msg = 'Bad received packet (%s)' % e\n"
- " print >>sys.stderr, '%s, %s bytes:' % (msg, len(data))\n"
+ " print('%s, %s bytes:' % (msg, len(data)), file=sys.stderr)\n"
" showmax = 40\n"
// We've observed failures with very large packets;
// dumping the entire packet wastes time and space.
@@ -167,12 +167,12 @@ namespace tut
" data = data[:trunc]\n"
" ellipsis = '... (%s more)' % (length - trunc)\n"
" offset = -showmax\n"
- " for offset in xrange(0, len(data)-showmax, showmax):\n"
- " print >>sys.stderr, '%04d: %r +' % \\\n"
- " (offset, data[offset:offset+showmax])\n"
+ " for offset in range(0, len(data)-showmax, showmax):\n"
+ " print('%04d: %r +' % \\\n"
+ " (offset, data[offset:offset+showmax]), file=sys.stderr)\n"
" offset += showmax\n"
- " print >>sys.stderr, '%04d: %r%s' % \\\n"
- " (offset, data[offset:], ellipsis)\n"
+ " print('%04d: %r%s' % \\\n"
+ " (offset, data[offset:], ellipsis), file=sys.stderr)\n"
" raise ParseError(msg, data)\n"
"\n"
"# deal with initial stdin message\n"
@@ -189,7 +189,7 @@ namespace tut
" sys.stdout.flush()\n"
"\n"
"def send(pump, data):\n"
- " put(llsd.format_notation(dict(pump=pump, data=data)))\n"
+ " put(llsd.format_notation(dict(pump=pump, data=data)).decode())\n"
"\n"
"def request(pump, data):\n"
" # we expect 'data' is a dict\n"
@@ -253,7 +253,7 @@ namespace tut
{
set_test_name("bad stdout protocol");
NamedTempFile script("py",
- "print 'Hello from Python!'\n");
+ "print('Hello from Python!')\n");
CaptureLog log(LLError::LEVEL_WARN);
waitfor(LLLeap::create(get_test_name(),
sv(list_of(PYTHON)(script.getName()))));
@@ -438,8 +438,8 @@ namespace tut
// guess how many messages it will take to
// accumulate BUFFERED_LENGTH
"count = int(" << BUFFERED_LENGTH << "/samplen)\n"
- "print >>sys.stderr, 'Sending %s requests' % count\n"
- "for i in xrange(count):\n"
+ "print('Sending %s requests' % count, file=sys.stderr)\n"
+ "for i in range(count):\n"
" request('" << api.getName() << "', dict(reqid=i))\n"
// The assumption in this specific test that
// replies will arrive in the same order as
@@ -450,7 +450,7 @@ namespace tut
// arbitrary order, and we'd have to tick them
// off from a set.
"result = ''\n"
- "for i in xrange(count):\n"
+ "for i in range(count):\n"
" resp = get()\n"
" if resp['data']['reqid'] != i:\n"
" result = 'expected reqid=%s in %s' % (i, resp)\n"
@@ -476,13 +476,13 @@ namespace tut
"desired = int(sys.argv[1])\n"
// 7 chars per item: 6 digits, 1 comma
"count = int((desired - 50)/7)\n"
- "large = ''.join('%06d,' % i for i in xrange(count))\n"
+ "large = ''.join('%06d,' % i for i in range(count))\n"
// Pass 'large' as reqid because we know the API
// will echo reqid, and we want to receive it back.
"request('" << api.getName() << "', dict(reqid=large))\n"
"try:\n"
" resp = get()\n"
- "except ParseError, e:\n"
+ "except ParseError as e:\n"
" # try to find where e.data diverges from expectation\n"
// Normally we'd expect a 'pump' key in there,
// too, with value replypump(). But Python
@@ -493,17 +493,18 @@ namespace tut
// strange.
" expect = llsd.format_notation(dict(data=dict(reqid=large)))\n"
" chunk = 40\n"
- " for offset in xrange(0, max(len(e.data), len(expect)), chunk):\n"
+ " for offset in range(0, max(len(e.data), len(expect)), chunk):\n"
" if e.data[offset:offset+chunk] != \\\n"
" expect[offset:offset+chunk]:\n"
- " print >>sys.stderr, 'Offset %06d: expect %r,\\n'\\\n"
+ " print('Offset %06d: expect %r,\\n'\\\n"
" ' get %r' %\\\n"
" (offset,\n"
" expect[offset:offset+chunk],\n"
- " e.data[offset:offset+chunk])\n"
+ " e.data[offset:offset+chunk]),\n"
+ " file=sys.stderr)\n"
" break\n"
" else:\n"
- " print >>sys.stderr, 'incoming data matches expect?!'\n"
+ " print('incoming data matches expect?!', file=sys.stderr)\n"
" send('" << result.getName() << "', '%s: %s' % (e.__class__.__name__, e))\n"
" sys.exit(1)\n"
"\n"
@@ -512,7 +513,7 @@ namespace tut
" send('" << result.getName() << "', '')\n"
" sys.exit(0)\n"
// Here we know echoed did NOT match; try to find where
- "for i in xrange(count):\n"
+ "for i in range(count):\n"
" start = 7*i\n"
" end = 7*(i+1)\n"
" if end > len(echoed)\\\n"
diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index f0eafa8201..e530975e86 100644
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -360,10 +360,10 @@ namespace tut
"import time" EOL
EOL
"time.sleep(2)" EOL
- "print >>sys.stdout, 'stdout after wait'" EOL
+ "print('stdout after wait', file=sys.stdout)" EOL
"sys.stdout.flush()" EOL
"time.sleep(2)" EOL
- "print >>sys.stderr, 'stderr after wait'" EOL
+ "print('stderr after wait', file=sys.stderr)" EOL
"sys.stderr.flush()" EOL
);
@@ -381,7 +381,11 @@ namespace tut
std::vector argv;
apr_proc_t child;
+#if defined(LL_WINDOWS)
argv.push_back("python");
+#else
+ argv.push_back("python3");
+#endif
// Have to have a named copy of this std::string so its c_str() value
// will persist.
std::string scriptname(script.getName());
@@ -573,7 +577,7 @@ namespace tut
// note nonstandard output-file arg!
"with open(sys.argv[3], 'w') as f:\n"
" for arg in sys.argv[1:]:\n"
- " print >>f, arg\n");
+ " print(arg, file=f)\n");
// We expect that PythonProcessLauncher has already appended
// its own NamedTempFile to mParams.args (sys.argv[0]).
py.mParams.args.add("first arg"); // sys.argv[1]
@@ -742,7 +746,7 @@ namespace tut
"with open(sys.argv[1], 'w') as f:\n"
" f.write('ok')\n"
"# wait for 'go' from test program\n"
- "for i in xrange(60):\n"
+ "for i in range(60):\n"
" time.sleep(1)\n"
" with open(sys.argv[2]) as f:\n"
" go = f.read()\n"
@@ -804,7 +808,7 @@ namespace tut
"with open(sys.argv[1], 'w') as f:\n"
" f.write('ok')\n"
"# wait for 'go' from test program\n"
- "for i in xrange(60):\n"
+ "for i in range(60):\n"
" time.sleep(1)\n"
" with open(sys.argv[2]) as f:\n"
" go = f.read()\n"
@@ -857,7 +861,7 @@ namespace tut
set_test_name("'bogus' test");
CaptureLog recorder;
PythonProcessLauncher py(get_test_name(),
- "print 'Hello world'\n");
+ "print('Hello world')\n");
py.mParams.files.add(LLProcess::FileParam("bogus"));
py.mPy = LLProcess::create(py.mParams);
ensure("should have rejected 'bogus'", ! py.mPy);
@@ -872,7 +876,7 @@ namespace tut
// Replace this test with one or more real 'file' tests when we
// implement 'file' support
PythonProcessLauncher py(get_test_name(),
- "print 'Hello world'\n");
+ "print('Hello world')\n");
py.mParams.files.add(LLProcess::FileParam());
py.mParams.files.add(LLProcess::FileParam("file"));
py.mPy = LLProcess::create(py.mParams);
@@ -887,7 +891,7 @@ namespace tut
// implement 'tpipe' support
CaptureLog recorder;
PythonProcessLauncher py(get_test_name(),
- "print 'Hello world'\n");
+ "print('Hello world')\n");
py.mParams.files.add(LLProcess::FileParam());
py.mParams.files.add(LLProcess::FileParam("tpipe"));
py.mPy = LLProcess::create(py.mParams);
@@ -904,7 +908,7 @@ namespace tut
// implement 'npipe' support
CaptureLog recorder;
PythonProcessLauncher py(get_test_name(),
- "print 'Hello world'\n");
+ "print('Hello world')\n");
py.mParams.files.add(LLProcess::FileParam());
py.mParams.files.add(LLProcess::FileParam());
py.mParams.files.add(LLProcess::FileParam("npipe"));
@@ -980,7 +984,7 @@ namespace tut
{
set_test_name("get*Pipe() validation");
PythonProcessLauncher py(get_test_name(),
- "print 'this output is expected'\n");
+ "print('this output is expected)'\n");
py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for stdin
py.mParams.files.add(LLProcess::FileParam()); // inherit stdout
py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for stderr
@@ -1001,13 +1005,13 @@ namespace tut
set_test_name("talk to stdin/stdout");
PythonProcessLauncher py(get_test_name(),
"import sys, time\n"
- "print 'ok'\n"
+ "print('ok')\n"
"sys.stdout.flush()\n"
"# wait for 'go' from test program\n"
"go = sys.stdin.readline()\n"
"if go != 'go\\n':\n"
" sys.exit('expected \"go\", saw %r' % go)\n"
- "print 'ack'\n");
+ "print('ack')\n");
py.mParams.files.add(LLProcess::FileParam("pipe")); // stdin
py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
py.launch();
@@ -1118,7 +1122,7 @@ namespace tut
{
set_test_name("ReadPipe \"eof\" event");
PythonProcessLauncher py(get_test_name(),
- "print 'Hello from Python!'\n");
+ "print('Hello from Python!')\n");
py.mParams.files.add(LLProcess::FileParam()); // stdin
py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
py.launch();
diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
index 642c1c3879..c246f5ee56 100644
--- a/indra/llcommon/tests/llsdserialize_test.cpp
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -1795,7 +1795,7 @@ namespace tut
set_test_name("verify NamedTempFile");
python("platform",
"import sys\n"
- "print 'Running on', sys.platform\n");
+ "print('Running on', sys.platform)\n");
}
// helper for test<3>
@@ -1825,14 +1825,14 @@ namespace tut
const char pydata[] =
"def verify(iterable):\n"
" it = iter(iterable)\n"
- " assert it.next() == 17\n"
- " assert abs(it.next() - 3.14) < 0.01\n"
- " assert it.next() == '''\\\n"
+ " assert next(it) == 17\n"
+ " assert abs(next(it) - 3.14) < 0.01\n"
+ " assert next(it) == '''\\\n"
"This string\n"
"has several\n"
"lines.'''\n"
" try:\n"
- " it.next()\n"
+ " next(it)\n"
" except StopIteration:\n"
" pass\n"
" else:\n"
@@ -1855,7 +1855,7 @@ namespace tut
" yield llsd.parse(item)\n" <<
pydata <<
// Don't forget raw-string syntax for Windows pathnames.
- "verify(parse_each(open(r'" << file.getName() << "')))\n");
+ "verify(parse_each(open(r'" << file.getName() << "', 'rb')))\n");
}
template<> template<>
@@ -1870,7 +1870,6 @@ namespace tut
python("write Python notation",
placeholders::arg1 <<
- "from __future__ import with_statement\n" <<
import_llsd <<
"DATA = [\n"
" 17,\n"
@@ -1884,7 +1883,7 @@ namespace tut
// N.B. Using 'print' implicitly adds newlines.
"with open(r'" << file.getName() << "', 'w') as f:\n"
" for item in DATA:\n"
- " print >>f, llsd.format_notation(item)\n");
+ " print(llsd.format_notation(item).decode(), file=f)\n");
std::ifstream inf(file.getName().c_str());
LLSD item;
diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index 8eccae00c7..b94a243fb2 100644
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -508,7 +508,12 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
check_curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1);
check_curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str());
check_curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, getHandle());
+
+// Newer versions of curl are stricter with checkinng Cotent-Encoding: header
+// Aws returns Content-Encoding: binary/octet-stream which is no valid scheme defined by HTTP/1.1 (compress,deflate, gzip)
+#if LIBCURL_VERSION_NUM < 0x075100
check_curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
+#endif
check_curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1);
check_curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT);
diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp
index 61ba83594e..8012da4370 100644
--- a/indra/llcorehttp/httpcommon.cpp
+++ b/indra/llcorehttp/httpcommon.cpp
@@ -289,8 +289,12 @@ CURL *getCurlTemplateHandle()
check_curl_code(result, CURLOPT_NOSIGNAL);
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_NOPROGRESS, 1);
check_curl_code(result, CURLOPT_NOPROGRESS);
+// Newer versions of curl are stricter with checkinng Cotent-Encoding: header
+// Aws returns Content-Encoding: binary/octet-stream which is no valid scheme defined by HTTP/1.1 (compress,deflate, gzip)
+#if LIBCURL_VERSION_NUM < 0x075100
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_ENCODING, "");
check_curl_code(result, CURLOPT_ENCODING);
+#endif
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_AUTOREFERER, 1);
check_curl_code(result, CURLOPT_AUTOREFERER);
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_FOLLOWLOCATION, 1);
diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp
index 3cdd17919d..154f6b12e9 100644
--- a/indra/llcorehttp/tests/test_httprequest.hpp
+++ b/indra/llcorehttp/tests/test_httprequest.hpp
@@ -135,7 +135,9 @@ public:
}
}
std::ostringstream str;
- str << "Required header # " << i << " found in response";
+ str << "Required header #" << i << " "
+ << mHeadersRequired[i].first << "=" << mHeadersRequired[i].second
+ << " not found in response";
ensure(str.str(), found);
}
}
@@ -154,7 +156,9 @@ public:
mHeadersDisallowed[i].second))
{
std::ostringstream str;
- str << "Disallowed header # " << i << " not found in response";
+ str << "Disallowed header #" << i << " "
+ << mHeadersDisallowed[i].first << "=" << mHeadersDisallowed[i].second
+ << " found in response";
ensure(str.str(), false);
}
}
@@ -2127,6 +2131,17 @@ void HttpRequestTestObjectType::test<18>()
template <> template <>
void HttpRequestTestObjectType::test<19>()
{
+ // It appears that HttpRequest is fully capable of sending duplicate header values in violation of
+ // this test's expectations. Something needs to budge: is sending duplicate header values desired?
+ //
+ // Test server /reflect/ response headers (mirrored from request)
+ //
+ // X-Reflect-content-type: text/plain
+ // X-Reflect-content-type: text/html
+ // X-Reflect-content-type: application/llsd+xml
+ //
+ skip("FIXME: Bad assertions or broken functionality.");
+
ScopedCurlInit ready;
// Warmup boost::regex to pre-alloc memory for memory size tests
@@ -2307,6 +2322,17 @@ void HttpRequestTestObjectType::test<19>()
template <> template <>
void HttpRequestTestObjectType::test<20>()
{
+ // It appears that HttpRequest is fully capable of sending duplicate header values in violation of
+ // this test's expectations. Something needs to budge: is sending duplicate header values desired?
+ //
+ // Test server /reflect/ response headers (mirrored from request)
+ //
+ // X-Reflect-content-type: text/plain
+ // X-Reflect-content-type: text/html
+ // X-Reflect-content-type: application/llsd+xml
+ //
+ skip("FIXME: Bad assertions or broken functionality.");
+
ScopedCurlInit ready;
// Warmup boost::regex to pre-alloc memory for memory size tests
@@ -2512,6 +2538,17 @@ void HttpRequestTestObjectType::test<20>()
template <> template <>
void HttpRequestTestObjectType::test<21>()
{
+ // It appears that HttpRequest is fully capable of sending duplicate header values in violation of
+ // this test's expectations. Something needs to budge: is sending duplicate header values desired?
+ //
+ // Test server /reflect/ response headers (mirrored from request)
+ //
+ // X-Reflect-content-type: text/plain
+ // X-Reflect-content-type: text/html
+ // X-Reflect-content-type: application/llsd+xml
+ //
+ skip("FIXME: Bad assertions or broken functionality.");
+
ScopedCurlInit ready;
// Warmup boost::regex to pre-alloc memory for memory size tests
diff --git a/indra/llcorehttp/tests/test_llcorehttp_peer.py b/indra/llcorehttp/tests/test_llcorehttp_peer.py
index 493143641b..778de90962 100755
--- a/indra/llcorehttp/tests/test_llcorehttp_peer.py
+++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""\
@file test_llsdmessage_peer.py
@author Nat Goodspeed
@@ -34,11 +34,9 @@ import sys
import time
import select
import getopt
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+from io import StringIO
+from http.server import HTTPServer, BaseHTTPRequestHandler
+
from llbase.fastest_elementtree import parse as xml_parse
from llbase import llsd
@@ -97,13 +95,13 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
except (KeyError, ValueError):
return ""
max_chunk_size = 10*1024*1024
- L = []
+ L = bytes()
while size_remaining:
chunk_size = min(size_remaining, max_chunk_size)
chunk = self.rfile.read(chunk_size)
- L.append(chunk)
+ L += chunk
size_remaining -= len(chunk)
- return ''.join(L)
+ return L.decode("utf-8")
# end of swiped read() logic
def read_xml(self):
@@ -127,8 +125,8 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
try:
self.answer(dict(reply="success", status=200,
reason="Your GET operation worked"))
- except self.ignore_exceptions, e:
- print >> sys.stderr, "Exception during GET (ignoring): %s" % str(e)
+ except self.ignore_exceptions as e:
+ print("Exception during GET (ignoring): %s" % str(e), file=sys.stderr)
def do_POST(self):
# Read the provided POST data.
@@ -136,8 +134,8 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
try:
self.answer(dict(reply="success", status=200,
reason=self.read()))
- except self.ignore_exceptions, e:
- print >> sys.stderr, "Exception during POST (ignoring): %s" % str(e)
+ except self.ignore_exceptions as e:
+ print("Exception during POST (ignoring): %s" % str(e), file=sys.stderr)
def do_PUT(self):
# Read the provided PUT data.
@@ -145,8 +143,8 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
try:
self.answer(dict(reply="success", status=200,
reason=self.read()))
- except self.ignore_exceptions, e:
- print >> sys.stderr, "Exception during PUT (ignoring): %s" % str(e)
+ except self.ignore_exceptions as e:
+ print("Exception during PUT (ignoring): %s" % str(e), file=sys.stderr)
def answer(self, data, withdata=True):
debug("%s.answer(%s): self.path = %r", self.__class__.__name__, data, self.path)
@@ -221,7 +219,7 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
self.send_header("Content-type", "text/plain")
self.end_headers()
if body:
- self.wfile.write(body)
+ self.wfile.write(body.encode("utf-8"))
elif "fail" not in self.path:
data = data.copy() # we're going to modify
# Ensure there's a "reply" key in data, even if there wasn't before
@@ -255,9 +253,9 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
self.end_headers()
def reflect_headers(self):
- for name in self.headers.keys():
- # print "Header: %s: %s" % (name, self.headers[name])
- self.send_header("X-Reflect-" + name, self.headers[name])
+ for (name, val) in self.headers.items():
+ # print("Header: %s %s" % (name, val), file=sys.stderr)
+ self.send_header("X-Reflect-" + name, val)
if not VERBOSE:
# When VERBOSE is set, skip both these overrides because they exist to
@@ -283,10 +281,10 @@ class Server(HTTPServer):
# default behavior which *shouldn't* cause the program to return
# a failure status.
def handle_error(self, request, client_address):
- print '-'*40
- print 'Ignoring exception during processing of request from',
- print client_address
- print '-'*40
+ print('-'*40)
+ print('Ignoring exception during processing of request from %' % (client_address))
+ print('-'*40)
+
if __name__ == "__main__":
do_valgrind = False
@@ -307,7 +305,7 @@ if __name__ == "__main__":
# "Then there's Windows"
# Instantiate a Server(TestHTTPRequestHandler) on the first free port
# in the specified port range.
- httpd, port = freeport(xrange(8000, 8020), make_server)
+ httpd, port = freeport(range(8000, 8020), make_server)
# Pass the selected port number to the subject test program via the
# environment. We don't want to impose requirements on the test program's
diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp
index 9580c846fc..75ce6aa478 100644
--- a/indra/llfilesystem/lldir.cpp
+++ b/indra/llfilesystem/lldir.cpp
@@ -648,7 +648,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
llassert(0);
}
- if (prefix.empty())
+ if (prefix.empty() && location != LL_PATH_NONE) // avoid pointless warning when LL_PATH_NONE is used.
{
LL_WARNS() << ELLPathToString(location)
<< ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename
diff --git a/indra/llinventory/llfoldertype.cpp b/indra/llinventory/llfoldertype.cpp
index ec4aec10d9..650d8dda25 100644
--- a/indra/llinventory/llfoldertype.cpp
+++ b/indra/llinventory/llfoldertype.cpp
@@ -37,15 +37,22 @@
struct FolderEntry : public LLDictionaryEntry
{
FolderEntry(const std::string &type_name, // 8 character limit!
- bool is_protected) // can the viewer change categories of this type?
+ bool is_protected, // can the viewer change categories of this type?
+ bool is_automatic, // always made before first login?
+ bool is_singleton // should exist as a unique copy under root
+ )
:
LLDictionaryEntry(type_name),
- mIsProtected(is_protected)
+ mIsProtected(is_protected),
+ mIsAutomatic(is_automatic),
+ mIsSingleton(is_singleton)
{
llassert(type_name.length() <= 8);
}
const bool mIsProtected;
+ const bool mIsAutomatic;
+ const bool mIsSingleton;
};
class LLFolderDictionary : public LLSingleton,
@@ -59,52 +66,66 @@ protected:
}
};
+// Folder types
+//
+// PROTECTED means that folders of this type can't be moved, deleted
+// or otherwise modified by the viewer.
+//
+// SINGLETON means that there should always be exactly one folder of
+// this type, and it should be the root or a child of the root. This
+// is true for most types of folders.
+//
+// AUTOMATIC means that a copy of this folder should be created under
+// the root before the user ever logs in, and should never be created
+// from the viewer. A missing AUTOMATIC folder should be treated as a
+// fatal error by the viewer, since it indicates either corrupted
+// inventory or a failure in the inventory services.
+//
LLFolderDictionary::LLFolderDictionary()
{
- // TYPE NAME PROTECTED
- // |-----------|---------|
- addEntry(LLFolderType::FT_TEXTURE, new FolderEntry("texture", TRUE));
- addEntry(LLFolderType::FT_SOUND, new FolderEntry("sound", TRUE));
- addEntry(LLFolderType::FT_CALLINGCARD, new FolderEntry("callcard", TRUE));
- addEntry(LLFolderType::FT_LANDMARK, new FolderEntry("landmark", TRUE));
- addEntry(LLFolderType::FT_CLOTHING, new FolderEntry("clothing", TRUE));
- addEntry(LLFolderType::FT_OBJECT, new FolderEntry("object", TRUE));
- addEntry(LLFolderType::FT_NOTECARD, new FolderEntry("notecard", TRUE));
- addEntry(LLFolderType::FT_ROOT_INVENTORY, new FolderEntry("root_inv", TRUE));
- addEntry(LLFolderType::FT_LSL_TEXT, new FolderEntry("lsltext", TRUE));
- addEntry(LLFolderType::FT_BODYPART, new FolderEntry("bodypart", TRUE));
- addEntry(LLFolderType::FT_TRASH, new FolderEntry("trash", TRUE));
- addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new FolderEntry("snapshot", TRUE));
- addEntry(LLFolderType::FT_LOST_AND_FOUND, new FolderEntry("lstndfnd", TRUE));
- addEntry(LLFolderType::FT_ANIMATION, new FolderEntry("animatn", TRUE));
- addEntry(LLFolderType::FT_GESTURE, new FolderEntry("gesture", TRUE));
- addEntry(LLFolderType::FT_FAVORITE, new FolderEntry("favorite", TRUE));
+ // TYPE NAME, PROTECTED, AUTOMATIC, SINGLETON
+ addEntry(LLFolderType::FT_TEXTURE, new FolderEntry("texture", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_SOUND, new FolderEntry("sound", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_CALLINGCARD, new FolderEntry("callcard", TRUE, TRUE, FALSE));
+ addEntry(LLFolderType::FT_LANDMARK, new FolderEntry("landmark", TRUE, FALSE, FALSE));
+ addEntry(LLFolderType::FT_CLOTHING, new FolderEntry("clothing", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_OBJECT, new FolderEntry("object", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_NOTECARD, new FolderEntry("notecard", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_ROOT_INVENTORY, new FolderEntry("root_inv", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_LSL_TEXT, new FolderEntry("lsltext", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_BODYPART, new FolderEntry("bodypart", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_TRASH, new FolderEntry("trash", TRUE, FALSE, TRUE));
+ addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new FolderEntry("snapshot", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_LOST_AND_FOUND, new FolderEntry("lstndfnd", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_ANIMATION, new FolderEntry("animatn", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_GESTURE, new FolderEntry("gesture", TRUE, TRUE, TRUE));
+ addEntry(LLFolderType::FT_FAVORITE, new FolderEntry("favorite", TRUE, FALSE, TRUE));
for (S32 ensemble_num = S32(LLFolderType::FT_ENSEMBLE_START); ensemble_num <= S32(LLFolderType::FT_ENSEMBLE_END); ensemble_num++)
{
- addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE));
+ addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE, FALSE, FALSE)); // Not used
}
- addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
- addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
- addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE));
+ addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE, FALSE, TRUE));
+ addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE, FALSE, FALSE));
+ addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE, FALSE, TRUE));
- addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE));
+ addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE, FALSE, FALSE)); // Not used?
- addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE));
- addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", FALSE)); // Make obsolete Merchant Outbox folder deletable
+ addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE, FALSE, TRUE));
+ addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", FALSE, FALSE, FALSE)); // Make obsolete Merchant Outbox folder deletable
- addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE));
+ addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE, FALSE, FALSE));
- addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new FolderEntry("merchant", FALSE));
- addEntry(LLFolderType::FT_MARKETPLACE_STOCK, new FolderEntry("stock", FALSE));
- addEntry(LLFolderType::FT_MARKETPLACE_VERSION, new FolderEntry("version", FALSE));
+ addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new FolderEntry("merchant", FALSE, FALSE, FALSE));
+ addEntry(LLFolderType::FT_MARKETPLACE_STOCK, new FolderEntry("stock", FALSE, FALSE, FALSE));
+ addEntry(LLFolderType::FT_MARKETPLACE_VERSION, new FolderEntry("version", FALSE, FALSE, FALSE));
- addEntry(LLFolderType::FT_SETTINGS, new FolderEntry("settings", TRUE));
+ addEntry(LLFolderType::FT_SETTINGS, new FolderEntry("settings", TRUE, FALSE, TRUE));
- addEntry(LLFolderType::FT_MY_SUITCASE, new FolderEntry("suitcase", TRUE)); // OpenSim HG-support
+ addEntry(LLFolderType::FT_MY_SUITCASE, new FolderEntry("suitcase", TRUE, FALSE, TRUE)); // OpenSim HG-support
- addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
+ addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE, FALSE, FALSE));
};
// static
@@ -128,8 +149,8 @@ const std::string &LLFolderType::lookup(LLFolderType::EType folder_type)
}
// static
-// Only ensembles and plain folders aren't protected. "Protected" means
-// you can't change certain properties such as their type.
+// Only plain folders and a few other types aren't protected. "Protected" means
+// you can't move, deleted, or change certain properties such as their type.
bool LLFolderType::lookupIsProtectedType(EType folder_type)
{
const LLFolderDictionary *dict = LLFolderDictionary::getInstance();
@@ -140,6 +161,32 @@ bool LLFolderType::lookupIsProtectedType(EType folder_type)
}
return true;
}
+
+// static
+// Is this folder type automatically created outside the viewer?
+bool LLFolderType::lookupIsAutomaticType(EType folder_type)
+{
+ const LLFolderDictionary *dict = LLFolderDictionary::getInstance();
+ const FolderEntry *entry = dict->lookup(folder_type);
+ if (entry)
+ {
+ return entry->mIsAutomatic;
+ }
+ return true;
+}
+
+// static
+// Should this folder always exist as a single copy under (or as) the root?
+bool LLFolderType::lookupIsSingletonType(EType folder_type)
+{
+ const LLFolderDictionary *dict = LLFolderDictionary::getInstance();
+ const FolderEntry *entry = dict->lookup(folder_type);
+ if (entry)
+ {
+ return entry->mIsSingleton;
+ }
+ return true;
+}
// static
bool LLFolderType::lookupIsEnsembleType(EType folder_type)
diff --git a/indra/llinventory/llfoldertype.h b/indra/llinventory/llfoldertype.h
index 0f231a76dd..c3edac9dbf 100644
--- a/indra/llinventory/llfoldertype.h
+++ b/indra/llinventory/llfoldertype.h
@@ -110,6 +110,8 @@ public:
static const std::string& lookup(EType folder_type);
static bool lookupIsProtectedType(EType folder_type);
+ static bool lookupIsAutomaticType(EType folder_type);
+ static bool lookupIsSingletonType(EType folder_type);
static bool lookupIsEnsembleType(EType folder_type);
static LLAssetType::EType folderTypeToAssetType(LLFolderType::EType folder_type);
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 7c6a5a46c4..a613ef0c59 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2458,7 +2458,14 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
//copy out indices
- face.resizeIndices(idx.size()/2);
+ S32 num_indices = idx.size() / 2;
+ face.resizeIndices(num_indices);
+
+ if (num_indices > 2 && !face.mIndices)
+ {
+ LL_WARNS() << "Failed to allocate " << num_indices << " indices for face index: " << i << " Total: " << face_count << LL_ENDL;
+ continue;
+ }
if (idx.empty() || face.mNumIndices < 3)
{ //why is there an empty index list?
@@ -2477,6 +2484,13 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
U32 num_verts = pos.size()/(3*2);
face.resizeVertices(num_verts);
+ if (num_verts > 0 && !face.mPositions)
+ {
+ LL_WARNS() << "Failed to allocate " << num_verts << " vertices for face index: " << i << " Total: " << face_count << LL_ENDL;
+ face.resizeIndices(0);
+ continue;
+ }
+
LLVector3 minp;
LLVector3 maxp;
LLVector2 min_tc;
@@ -2578,6 +2592,13 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
if (mdl[i].has("Weights"))
{
face.allocateWeights(num_verts);
+ if (!face.mWeights && num_verts)
+ {
+ LL_WARNS() << "Failed to allocate " << num_verts << " weights for face index: " << i << " Total: " << face_count << LL_ENDL;
+ face.resizeIndices(0);
+ face.resizeVertices(0);
+ continue;
+ }
LLSD::Binary weights = mdl[i]["Weights"];
@@ -5376,22 +5397,23 @@ bool LLVolumeFace::cacheOptimize()
{
triangle_data.resize(mNumIndices / 3);
vertex_data.resize(mNumVertices);
- }
- catch (std::bad_alloc&)
- {
- LL_WARNS("LLVOLUME") << "Resize failed" << LL_ENDL;
- return false;
- }
- for (U32 i = 0; i < mNumIndices; i++)
- { //populate vertex data and triangle data arrays
- U16 idx = mIndices[i];
- U32 tri_idx = i/3;
+ for (U32 i = 0; i < mNumIndices; i++)
+ { //populate vertex data and triangle data arrays
+ U16 idx = mIndices[i];
+ U32 tri_idx = i / 3;
- vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx]));
- vertex_data[idx].mIdx = idx;
- triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]);
- }
+ vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx]));
+ vertex_data[idx].mIdx = idx;
+ triangle_data[tri_idx].mVertex[i % 3] = &(vertex_data[idx]);
+ }
+ }
+ catch (std::bad_alloc&)
+ {
+ // resize or push_back failed
+ LL_WARNS("LLVOLUME") << "Resize for " << mNumVertices << " vertices failed" << LL_ENDL;
+ return false;
+ }
/*F32 pre_acmr = 1.f;
//measure cache misses from before rebuild
@@ -6435,8 +6457,18 @@ void LLVolumeFace::resizeVertices(S32 num_verts)
mTexCoords = NULL;
}
- mNumVertices = num_verts;
- mNumAllocatedVertices = num_verts;
+
+ if (mPositions)
+ {
+ mNumVertices = num_verts;
+ mNumAllocatedVertices = num_verts;
+ }
+ else
+ {
+ // Either num_verts is zero or allocation failure
+ mNumVertices = 0;
+ mNumAllocatedVertices = 0;
+ }
// Force update
mJointRiggingInfoTab.clear();
@@ -6537,7 +6569,15 @@ void LLVolumeFace::resizeIndices(S32 num_indices)
mIndices = NULL;
}
- mNumIndices = num_indices;
+ if (mIndices)
+ {
+ mNumIndices = num_indices;
+ }
+ else
+ {
+ // Either num_indices is zero or allocation failure
+ mNumIndices = 0;
+ }
}
void LLVolumeFace::pushIndex(const U16& idx)
diff --git a/indra/llmessage/llnamevalue.cpp b/indra/llmessage/llnamevalue.cpp
index c51883ee3d..6076439518 100644
--- a/indra/llmessage/llnamevalue.cpp
+++ b/indra/llmessage/llnamevalue.cpp
@@ -35,6 +35,12 @@
#include "llstring.h"
#include "llstringtable.h"
+// Suppress warnings about the string fiddling
+#if LL_LINUX
+#pragma GCC diagnostic ignored "-Wstringop-truncation"
+#endif
+//
+
// Anonymous enumeration to provide constants in this file.
// *NOTE: These values may be used in sscanf statements below as their
// value-1, so search for '2047' if you cange NV_BUFFER_LEN or '63' if
diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py
index 9cd2959ea1..5ba0749e31 100755
--- a/indra/llmessage/tests/test_llsdmessage_peer.py
+++ b/indra/llmessage/tests/test_llsdmessage_peer.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""\
@file test_llsdmessage_peer.py
@author Nat Goodspeed
@@ -31,7 +31,7 @@ $/LicenseInfo$
import os
import sys
-from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+from http.server import HTTPServer, BaseHTTPRequestHandler
from llbase.fastest_elementtree import parse as xml_parse
from llbase import llsd
@@ -165,7 +165,7 @@ if __name__ == "__main__":
# "Then there's Windows"
# Instantiate a Server(TestHTTPRequestHandler) on the first free port
# in the specified port range.
- httpd, port = freeport(xrange(8000, 8020), make_server)
+ httpd, port = freeport(range(8000, 8020), make_server)
# Pass the selected port number to the subject test program via the
# environment. We don't want to impose requirements on the test program's
diff --git a/indra/llmessage/tests/testrunner.py b/indra/llmessage/tests/testrunner.py
index c25945067e..47c09ca245 100755
--- a/indra/llmessage/tests/testrunner.py
+++ b/indra/llmessage/tests/testrunner.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""\
@file testrunner.py
@author Nat Goodspeed
@@ -41,7 +41,7 @@ VERBOSE = not re.match(r"(0|off|false|quiet)$", VERBOSE, re.IGNORECASE)
if VERBOSE:
def debug(fmt, *args):
- print fmt % args
+ print(fmt % args)
sys.stdout.flush()
else:
debug = lambda *args: None
@@ -99,14 +99,14 @@ def freeport(portlist, expr):
# error because we can't return meaningful values. We have no 'port',
# therefore no 'expr(port)'.
portiter = iter(portlist)
- port = portiter.next()
+ port = next(portiter)
while True:
try:
# If this value of port works, return as promised.
value = expr(port)
- except socket.error, err:
+ except socket.error as err:
# Anything other than 'Address already in use', propagate
if err.args[0] != errno.EADDRINUSE:
raise
@@ -117,9 +117,9 @@ def freeport(portlist, expr):
type, value, tb = sys.exc_info()
try:
try:
- port = portiter.next()
+ port = next(portiter)
except StopIteration:
- raise type, value, tb
+ raise type(value).with_traceback(tb)
finally:
# Clean up local traceback, see docs for sys.exc_info()
del tb
@@ -138,7 +138,7 @@ def freeport(portlist, expr):
# If we've actually arrived at this point, portiter.next() delivered a
# new port value. Loop back to pass that to expr(port).
- except Exception, err:
+ except Exception as err:
debug("*** freeport() raising %s: %s", err.__class__.__name__, err)
raise
@@ -227,13 +227,13 @@ def test_freeport():
def exc(exception_class, *args):
try:
yield
- except exception_class, err:
+ except exception_class as err:
for i, expected_arg in enumerate(args):
assert expected_arg == err.args[i], \
"Raised %s, but args[%s] is %r instead of %r" % \
(err.__class__.__name__, i, err.args[i], expected_arg)
- print "Caught expected exception %s(%s)" % \
- (err.__class__.__name__, ', '.join(repr(arg) for arg in err.args))
+ print("Caught expected exception %s(%s)" % \
+ (err.__class__.__name__, ', '.join(repr(arg) for arg in err.args)))
else:
assert False, "Failed to raise " + exception_class.__class__.__name__
@@ -270,18 +270,18 @@ def test_freeport():
# This is the magic exception that should prompt us to retry
inuse = socket.error(errno.EADDRINUSE, 'Address already in use')
# Get the iterator to our ports list so we can check later if we've used all
- ports = iter(xrange(5))
+ ports = iter(range(5))
with exc(socket.error, errno.EADDRINUSE):
freeport(ports, lambda port: raiser(inuse))
# did we entirely exhaust 'ports'?
with exc(StopIteration):
- ports.next()
+ next(ports)
- ports = iter(xrange(2))
+ ports = iter(range(2))
# Any exception but EADDRINUSE should quit immediately
with exc(SomeError):
freeport(ports, lambda port: raiser(SomeError()))
- assert_equals(ports.next(), 1)
+ assert_equals(next(ports), 1)
# ----------- freeport() with platform-dependent socket stuff ------------
# This is what we should've had unit tests to begin with (see CHOP-661).
@@ -290,14 +290,14 @@ def test_freeport():
sock.bind(('127.0.0.1', port))
return sock
- bound0, port0 = freeport(xrange(7777, 7780), newbind)
+ bound0, port0 = freeport(range(7777, 7780), newbind)
assert_equals(port0, 7777)
- bound1, port1 = freeport(xrange(7777, 7780), newbind)
+ bound1, port1 = freeport(range(7777, 7780), newbind)
assert_equals(port1, 7778)
- bound2, port2 = freeport(xrange(7777, 7780), newbind)
+ bound2, port2 = freeport(range(7777, 7780), newbind)
assert_equals(port2, 7779)
with exc(socket.error, errno.EADDRINUSE):
- bound3, port3 = freeport(xrange(7777, 7780), newbind)
+ bound3, port3 = freeport(range(7777, 7780), newbind)
if __name__ == "__main__":
test_freeport()
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index 7088cf4d4b..7ebd73f313 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -82,8 +82,29 @@ protected:
};
+
+class LLPluginProcessCreationThread : public LLThread
+{
+public:
+ LLPluginProcessCreationThread(LLPluginProcessParent *parent) :
+ LLThread("LLPluginProcessCreationThread", gAPRPoolp),
+ pParent(parent)
+ {
+ }
+protected:
+ // Inherited from LLThread, should run once
+ /*virtual*/ void run(void)
+ {
+ pParent->createPluginProcess();
+ }
+private:
+ LLPluginProcessParent *pParent;
+
+};
+
LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
- mIncomingQueueMutex()
+ mIncomingQueueMutex(),
+ pProcessCreationThread(NULL)
{
if(!sInstancesMutex)
{
@@ -112,6 +133,18 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
LLPluginProcessParent::~LLPluginProcessParent()
{
LL_DEBUGS("Plugin") << "destructor" << LL_ENDL;
+ if (pProcessCreationThread)
+ {
+ if (!pProcessCreationThread->isStopped())
+ {
+ // Shouldn't happen at this stage
+ LL_WARNS("Plugin") << "Shutting down active pProcessCreationThread" << LL_ENDL;
+ pProcessCreationThread->shutdown();
+ ms_sleep(20);
+ }
+ delete pProcessCreationThread;
+ pProcessCreationThread = NULL;
+ }
// Destroy any remaining shared memory regions
sharedMemoryRegionsType::iterator iter;
@@ -162,6 +195,7 @@ void LLPluginProcessParent::shutdown()
&& state != STATE_ERROR)
{
(*it).second->setState(STATE_GOODBYE);
+ (*it).second->mOwner = NULL;
}
if (state != STATE_DONE)
{
@@ -321,6 +355,35 @@ bool LLPluginProcessParent::accept()
return result;
}
+bool LLPluginProcessParent::createPluginProcess()
+{
+ if (!mProcess)
+ {
+ // Only argument to the launcher is the port number we're listening on
+ mProcessParams.args.add(stringize(mBoundPort));
+ mProcess = LLProcess::create(mProcessParams);
+ return mProcess != NULL;
+ }
+
+ return false;
+}
+
+void LLPluginProcessParent::clearProcessCreationThread()
+{
+ if (pProcessCreationThread)
+ {
+ if (!pProcessCreationThread->isStopped())
+ {
+ pProcessCreationThread->shutdown();
+ }
+ else
+ {
+ delete pProcessCreationThread;
+ pProcessCreationThread = NULL;
+ }
+ }
+}
+
void LLPluginProcessParent::idle(void)
{
bool idle_again;
@@ -328,8 +391,9 @@ void LLPluginProcessParent::idle(void)
do
{
// process queued messages
- mIncomingQueueMutex.lock();
- while(!mIncomingQueue.empty())
+ // Inside main thread, it is preferable not to block it on mutex.
+ bool locked = mIncomingQueueMutex.trylock();
+ while(locked && !mIncomingQueue.empty())
{
LLPluginMessage message = mIncomingQueue.front();
mIncomingQueue.pop();
@@ -337,10 +401,13 @@ void LLPluginProcessParent::idle(void)
receiveMessage(message);
- mIncomingQueueMutex.lock();
+ locked = mIncomingQueueMutex.trylock();
}
- mIncomingQueueMutex.unlock();
+ if (locked)
+ {
+ mIncomingQueueMutex.unlock();
+ }
// Give time to network processing
if(mMessagePipe)
@@ -349,7 +416,10 @@ void LLPluginProcessParent::idle(void)
mMessagePipe->pumpOutput();
// Only do input processing here if this instance isn't in a pollset.
- if(!mPolledInput)
+ // If viewer and plugin are both shutting down, don't process further
+ // input, viewer won't be able to handle it.
+ if(!mPolledInput
+ && !(mState >= STATE_GOODBYE && LLApp::isExiting()))
{
mMessagePipe->pumpInput();
}
@@ -488,15 +558,30 @@ void LLPluginProcessParent::idle(void)
case STATE_LISTENING:
{
// Launch the plugin process.
+ if (mDebug && !pProcessCreationThread)
+ {
+ createPluginProcess();
+ if (!mProcess)
+ {
+ errorState();
+ }
+ }
+ else if (pProcessCreationThread == NULL)
+ {
+ // exe plugin process allocation can be hindered by a number
+ // of factors, don't hold whole viewer because of it, use thread
+ pProcessCreationThread = new LLPluginProcessCreationThread(this);
+ pProcessCreationThread->start();
+ }
+ else if (!mProcess && pProcessCreationThread->isStopped())
+ {
+ delete pProcessCreationThread;
+ pProcessCreationThread = NULL;
+ errorState();
+ }
+
- // Only argument to the launcher is the port number we're listening on
- mProcessParams.args.add(stringize(mBoundPort));
-
- if (! (mProcess = LLProcess::create(mProcessParams)))
- {
- errorState();
- }
- else
+ if (mProcess)
{
if(mDebug)
{
@@ -525,6 +610,15 @@ void LLPluginProcessParent::idle(void)
// This will allow us to time out if the process never starts.
mHeartbeat.start();
mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
+
+ // pProcessCreationThread should have stopped by this point,
+ // but check just in case it paused on statistics sync
+ if (pProcessCreationThread && pProcessCreationThread->isStopped())
+ {
+ delete pProcessCreationThread;
+ pProcessCreationThread = NULL;
+ }
+
setState(STATE_LAUNCHED);
}
}
@@ -627,6 +721,7 @@ void LLPluginProcessParent::idle(void)
killSockets();
setState(STATE_DONE);
dirtyPollSet();
+ clearProcessCreationThread();
break;
case STATE_DONE:
diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h
index 7fde43a149..b70dff86c3 100644
--- a/indra/llplugin/llpluginprocessparent.h
+++ b/indra/llplugin/llpluginprocessparent.h
@@ -69,6 +69,11 @@ public:
const std::string &plugin_filename,
bool debug);
+ // Creates a process
+ // returns true if process already exists or if created,
+ // false if failed to create
+ bool createPluginProcess();
+
void idle(void);
// returns true if the plugin is on its way to steady state
@@ -163,12 +168,15 @@ private:
bool accept();
+ void clearProcessCreationThread();
+
LLSocket::ptr_t mListenSocket;
LLSocket::ptr_t mSocket;
U32 mBoundPort;
LLProcess::Params mProcessParams;
LLProcessPtr mProcess;
+ LLThread *pProcessCreationThread;
std::string mPluginFile;
std::string mPluginDir;
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index bc133d3692..0a9d4bef03 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -242,6 +242,17 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector& fa
}
LLVolumeFace::VertexMapData::PointMap point_map;
+
+ if (idx_stride <= 0
+ || (pos_source && pos_offset >= idx_stride)
+ || (tc_source && tc_offset >= idx_stride)
+ || (norm_source && norm_offset >= idx_stride))
+ {
+ // Looks like these offsets should fit inside idx_stride
+ // Might be good idea to also check idx.getCount()%idx_stride != 0
+ LL_WARNS() << "Invalid pos_offset " << pos_offset << ", tc_offset " << tc_offset << " or norm_offset " << norm_offset << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
for (U32 i = 0; i < idx.getCount(); i += idx_stride)
{
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index 5193b16a1e..da375292e8 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -606,6 +606,58 @@ void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD&
}
}
+// static
+// Same as toggleInstanceOrBringToFront but does not close floater.
+// unlike showInstance() does not trigger onOpen() if already open
+void LLFloaterReg::showInstanceOrBringToFront(const LLSD& sdname, const LLSD& key)
+{
+ std::string name = sdname.asString();
+ LLFloater* instance = getInstance(name, key);
+
+
+ if (!instance)
+ {
+ LL_DEBUGS() << "Unable to get instance of floater '" << name << "'" << LL_ENDL;
+ return;
+ }
+
+ // If hosted, we need to take that into account
+ LLFloater* host = instance->getHost();
+
+ if (host)
+ {
+ if (host->isMinimized() || !host->isShown() || !host->isFrontmost())
+ {
+ host->setMinimized(FALSE);
+ instance->openFloater(key);
+ instance->setVisibleAndFrontmost(true, key);
+ }
+ else if (!instance->getVisible())
+ {
+ instance->openFloater(key);
+ instance->setVisibleAndFrontmost(true, key);
+ instance->setFocus(TRUE);
+ }
+ }
+ else
+ {
+ if (instance->isMinimized())
+ {
+ instance->setMinimized(FALSE);
+ instance->setVisibleAndFrontmost(true, key);
+ }
+ else if (!instance->isShown())
+ {
+ instance->openFloater(key);
+ instance->setVisibleAndFrontmost(true, key);
+ }
+ else if (!instance->isFrontmost())
+ {
+ instance->setVisibleAndFrontmost(true, key);
+ }
+ }
+}
+
// static
U32 LLFloaterReg::getVisibleFloaterInstanceCount()
{
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index a76eb5c79b..6ebebf3fe3 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -158,6 +158,7 @@ public:
// Callback wrappers
static void toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD());
+ static void showInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD());
// Typed find / get / show
template
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index de77a2c98c..6028986eaf 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -261,6 +261,8 @@ LLFolderView::LLFolderView(const Params& p)
mPopupMenuHandle = menu->getHandle();
mViewModelItem->openItem();
+
+ mAreChildrenInited = true; // root folder is a special case due to not being loaded normally, assume that it's inited.
}
// Destroys the object
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 64d702a612..3378bcaadb 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -139,7 +139,6 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mCutGeneration(0),
mLabelStyle( LLFontGL::NORMAL ),
mHasVisibleChildren(FALSE),
- mIsFolderComplete(true),
mLocalIndentation(p.folder_indentation),
mIndentation(0),
mItemHeight(p.item_height),
@@ -1118,11 +1117,11 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ):
mCurHeight(0.f),
mTargetHeight(0.f),
mAutoOpenCountdown(0.f),
+ mIsFolderComplete(false), // folder might have children that are not loaded yet.
+ mAreChildrenInited(false), // folder might have children that are not built yet.
mLastArrangeGeneration( -1 ),
mLastCalculatedWidth(0)
{
- // folder might have children that are not loaded yet. Mark it as incomplete until chance to check it.
- mIsFolderComplete = false;
}
void LLFolderViewFolder::updateLabelRotation()
@@ -1178,13 +1177,16 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height )
{
// Sort before laying out contents
// Note that we sort from the root (CHUI-849)
- getRoot()->getFolderViewModel()->sort(this);
+ if (mAreChildrenInited)
+ {
+ getRoot()->getFolderViewModel()->sort(this);
+ }
LL_RECORD_BLOCK_TIME(FTM_ARRANGE);
// evaluate mHasVisibleChildren
mHasVisibleChildren = false;
- if (getViewModelItem()->descendantsPassedFilter())
+ if (mAreChildrenInited && getViewModelItem()->descendantsPassedFilter())
{
// We have to verify that there's at least one child that's not filtered out
bool found = false;
@@ -1210,7 +1212,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height )
mHasVisibleChildren = found;
}
- if (!mIsFolderComplete)
+ if (!mIsFolderComplete && mAreChildrenInited)
{
mIsFolderComplete = getFolderViewModel()->isFolderComplete(this);
}
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index 72bb926163..2d36616e25 100644
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -120,7 +120,6 @@ protected:
F32 mControlLabelRotation;
LLFolderView* mRoot;
bool mHasVisibleChildren,
- mIsFolderComplete, // indicates that some children were not loaded/added yet
mIsCurSelection,
mDragAndDropTarget,
mIsMouseOverTitle,
@@ -229,7 +228,10 @@ public:
BOOL hasVisibleChildren() { return mHasVisibleChildren; }
// true if object can't have children
- BOOL isFolderComplete() { return mIsFolderComplete; }
+ virtual bool isFolderComplete() { return true; }
+ // true if object can't have children
+ virtual bool areChildrenInited() { return true; }
+ virtual void setChildrenInited(bool inited) { }
// Call through to the viewed object and return true if it can be
// removed. Returns true if it's removed.
@@ -349,6 +351,8 @@ protected:
S32 mLastArrangeGeneration;
S32 mLastCalculatedWidth;
// bool mNeedsSort; Unused.
+ bool mIsFolderComplete; // indicates that some children were not loaded/added yet
+ bool mAreChildrenInited; // indicates that no children were initialized
public:
typedef enum e_recurse_type
@@ -400,6 +404,13 @@ public:
// destroys this folder, and all children
virtual void destroyView();
+ // whether known children are fully loaded (arrange sets to true)
+ virtual bool isFolderComplete() { return mIsFolderComplete; }
+
+ // whether known children are fully built
+ virtual bool areChildrenInited() { return mAreChildrenInited; }
+ virtual void setChildrenInited(bool inited) { mAreChildrenInited = inited; }
+
// extractItem() removes the specified item from the folder, but
// doesn't delete it.
virtual void extractItem( LLFolderViewItem* item, bool deparent_model = true);
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 34d8ed6fef..d8d23ccd7d 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -500,8 +500,7 @@ LLNotification::LLNotification(const LLSDParamAdapter& p) :
mResponderObj(NULL),
mId(p.id.isProvided() ? p.id : LLUUID::generateNewID()),
mOfferFromAgent(p.offer_from_agent),
- mIsDND(p.is_dnd),
- mIsFromStorage(false)// FIRE-11339: Persisted group notifications get logged to IM on each login
+ mIsDND(p.is_dnd)
{
if (p.functor.name.isChosen())
{
@@ -1710,6 +1709,20 @@ void LLNotifications::add(const LLNotificationPtr pNotif)
updateItem(LLSD().with("sigtype", "add").with("id", pNotif->id()), pNotif);
}
+void LLNotifications::load(const LLNotificationPtr pNotif)
+{
+ if (pNotif == NULL) return;
+
+ // first see if we already have it -- if so, that's a problem
+ LLNotificationSet::iterator it=mItems.find(pNotif);
+ if (it != mItems.end())
+ {
+ LL_ERRS() << "Notification loaded a second time to the master notification channel." << LL_ENDL;
+ }
+
+ updateItem(LLSD().with("sigtype", "load").with("id", pNotif->id()), pNotif);
+}
+
void LLNotifications::cancel(LLNotificationPtr pNotif)
{
if (pNotif == NULL || pNotif->isCancelled()) return;
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 624c267f28..300a124d68 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -399,7 +399,6 @@ private:
LLNotificationResponderPtr mResponder;
bool mOfferFromAgent;
bool mIsDND;
- bool mIsFromStorage; // FIRE-11339: Persisted group notifications get logged to IM on each login
// a reference to the template
LLNotificationTemplatePtr mTemplatep;
@@ -557,18 +556,6 @@ public:
mIsDND = flag;
}
- // FIRE-11339: Persisted group notifications get logged to IM on each login
- bool isFromStorage() const
- {
- return mIsFromStorage;
- }
-
- void setIsFromStorage(bool logged)
- {
- mIsFromStorage = logged;
- }
- //
-
std::string getType() const;
std::string getMessage() const;
std::string getFooter() const;
@@ -936,6 +923,7 @@ public:
LLNotificationPtr add(const LLNotification::Params& p);
void add(const LLNotificationPtr pNotif);
+ void load(const LLNotificationPtr pNotif);
void cancel(LLNotificationPtr pNotif);
void cancelByName(const std::string& name);
void cancelByOwner(const LLUUID ownerId);
@@ -1139,6 +1127,11 @@ private:
mHistory.push_back(p);
}
+ void onLoad(LLNotificationPtr p)
+ {
+ mHistory.push_back(p);
+ }
+
std::vector mHistory;
};
diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index 61470d1440..f73c9aa539 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -83,6 +83,14 @@ const LLSD LLScrollListCell::getValue() const
return LLStringUtil::null;
}
+
+// virtual
+const LLSD LLScrollListCell::getAltValue() const
+{
+ return LLStringUtil::null;
+}
+
+
//
// LLScrollListIcon
//
@@ -245,6 +253,7 @@ U32 LLScrollListText::sCount = 0;
LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
: LLScrollListCell(p),
mText(p.label.isProvided() ? p.label() : p.value().asString()),
+ mAltText(p.alt_value().asString()),
mFont(p.font),
mColor(p.color),
mUseColor(p.color.isProvided()),
@@ -347,10 +356,22 @@ void LLScrollListText::setValue(const LLSD& text)
setText(text.asString());
}
+//virtual
+void LLScrollListText::setAltValue(const LLSD& text)
+{
+ mAltText = text.asString();
+}
+
//virtual
const LLSD LLScrollListText::getValue() const
{
- return LLSD(mText.getString());
+ return LLSD(mText.getString());
+}
+
+//virtual
+const LLSD LLScrollListText::getAltValue() const
+{
+ return LLSD(mAltText.getString());
}
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index 9a659dfd0d..2588da2331 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -61,6 +61,7 @@ public:
Optional userdata;
Optional value; // state of checkbox, icon id/name, date
+ Optional alt_value;
Optional label; // description or text
Optional tool_tip;
@@ -77,6 +78,7 @@ public:
enabled("enabled", true),
visible("visible", true),
value("value"),
+ alt_value("alt_value", ""),
label("label"),
tool_tip("tool_tip", ""),
font("font", LLFontGL::getFontSansSerifSmall()),
@@ -99,7 +101,9 @@ public:
virtual S32 getContentWidth() const { return 0; }
virtual S32 getHeight() const { return 0; }
virtual const LLSD getValue() const;
+ virtual const LLSD getAltValue() const;
virtual void setValue(const LLSD& value) { }
+ virtual void setAltValue(const LLSD& value) { }
virtual const std::string &getToolTip() const { return mToolTip; }
virtual void setToolTip(const std::string &str) { mToolTip = str; }
virtual BOOL getVisible() const { return TRUE; }
@@ -139,7 +143,9 @@ public:
/*virtual*/ S32 getContentWidth() const;
/*virtual*/ S32 getHeight() const;
/*virtual*/ void setValue(const LLSD& value);
+ /*virtual*/ void setAltValue(const LLSD& value);
/*virtual*/ const LLSD getValue() const;
+ /*virtual*/ const LLSD getAltValue() const;
/*virtual*/ BOOL getVisible() const;
/*virtual*/ void highlightText(S32 offset, S32 num_chars);
@@ -158,6 +164,7 @@ public:
protected:
LLUIString mText;
+ LLUIString mAltText;
S32 mTextWidth;
const LLFontGL* mFont;
LLColor4 mColor;
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 8407b30e4c..64ca9723cf 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -68,9 +68,10 @@ static LLDefaultChildRegistry::Register r("scroll_list");
// local structures & classes.
struct SortScrollListItem
{
- SortScrollListItem(const std::vector >& sort_orders,const LLScrollListCtrl::sort_signal_t* sort_signal)
+ SortScrollListItem(const std::vector >& sort_orders,const LLScrollListCtrl::sort_signal_t* sort_signal, bool alternate_sort)
: mSortOrders(sort_orders)
, mSortSignal(sort_signal)
+ , mAltSort(alternate_sort)
{}
bool operator()(const LLScrollListItem* i1, const LLScrollListItem* i2)
@@ -95,7 +96,14 @@ struct SortScrollListItem
}
else
{
- sort_result = order * LLStringUtil::compareDict(cell1->getValue().asString(), cell2->getValue().asString());
+ if (mAltSort && !cell1->getAltValue().asString().empty() && !cell2->getAltValue().asString().empty())
+ {
+ sort_result = order * LLStringUtil::compareDict(cell1->getAltValue().asString(), cell2->getAltValue().asString());
+ }
+ else
+ {
+ sort_result = order * LLStringUtil::compareDict(cell1->getValue().asString(), cell2->getValue().asString());
+ }
}
if (sort_result != 0)
{
@@ -111,6 +119,7 @@ struct SortScrollListItem
typedef std::vector > sort_order_t;
const LLScrollListCtrl::sort_signal_t* mSortSignal;
const sort_order_t& mSortOrders;
+ const bool mAltSort;
};
//---------------------------------------------------------------------------
@@ -219,6 +228,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
mSearchColumn(p.search_column),
mColumnPadding(p.column_padding),
mRowPadding(p.row_padding),
+ mAlternateSort(false),
mContextMenuType(MENU_NONE),
mIsFriendSignal(NULL),
// Fix for FS-specific people list (radar)
@@ -400,8 +410,7 @@ LLScrollListCtrl::~LLScrollListCtrl()
std::for_each(mItemList.begin(), mItemList.end(), DeletePointer());
mItemList.clear();
- std::for_each(mColumns.begin(), mColumns.end(), DeletePairedPointer());
- mColumns.clear();
+ clearColumns(); //clears columns and deletes headers
delete mIsFriendSignal;
}
@@ -3098,7 +3107,7 @@ void LLScrollListCtrl::updateSort() const
std::stable_sort(
mItemList.begin(),
mItemList.end(),
- SortScrollListItem(mSortColumns,mSortCallback));
+ SortScrollListItem(mSortColumns,mSortCallback, mAlternateSort));
mSorted = true;
}
@@ -3114,7 +3123,7 @@ void LLScrollListCtrl::sortOnce(S32 column, BOOL ascending)
std::stable_sort(
mItemList.begin(),
mItemList.end(),
- SortScrollListItem(sort_column,mSortCallback));
+ SortScrollListItem(sort_column,mSortCallback,mAlternateSort));
}
void LLScrollListCtrl::dirtyColumns()
@@ -3480,6 +3489,8 @@ void LLScrollListCtrl::clearColumns()
// Reset number of dynamic columns, too
mNumDynamicWidthColumns = 0;
+
+ dirtyColumns(); // Clears mColumnsIndexed
}
void LLScrollListCtrl::setColumnLabel(const std::string& column, const std::string& label)
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index af00f56db5..99ffa2a94f 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -421,6 +421,8 @@ public:
BOOL hasSortOrder() const;
void clearSortOrder();
+ void setAlternateSort() { mAlternateSort = true; }
+
S32 selectMultiple( uuid_vec_t ids );
// conceptually const, but mutates mItemList
void updateSort() const;
@@ -519,6 +521,8 @@ private:
bool mColumnsDirty;
bool mColumnWidthsDirty;
+ bool mAlternateSort;
+
mutable item_list mItemList;
LLScrollListItem *mLastSelected;
diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp
index 51c615dd00..e1360f80cd 100644
--- a/indra/llui/llscrolllistitem.cpp
+++ b/indra/llui/llscrolllistitem.cpp
@@ -44,7 +44,8 @@ LLScrollListItem::LLScrollListItem( const Params& p )
mSelectedIndex(-1),
mEnabled(p.enabled),
mUserdata(p.userdata),
- mItemValue(p.value)
+ mItemValue(p.value),
+ mItemAltValue(p.alt_value)
{
}
diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h
index d2c3dd7721..a3398305b1 100644
--- a/indra/llui/llscrolllistitem.h
+++ b/indra/llui/llscrolllistitem.h
@@ -55,6 +55,7 @@ public:
Optional enabled;
Optional userdata;
Optional value;
+ Optional alt_value;
Ignored name; // use for localization tools
Ignored type;
@@ -65,6 +66,7 @@ public:
Params()
: enabled("enabled", true),
value("value"),
+ alt_value("alt_value"),
name("name"),
type("type"),
length("length"),
@@ -97,6 +99,7 @@ public:
virtual LLUUID getUUID() const { return mItemValue.asUUID(); }
LLSD getValue() const { return mItemValue; }
+ LLSD getAltValue() const { return mItemAltValue; }
void setRect(LLRect rect) { mRectangle = rect; }
LLRect getRect() const { return mRectangle; }
@@ -131,6 +134,7 @@ private:
BOOL mEnabled;
void* mUserdata;
LLSD mItemValue;
+ LLSD mItemAltValue;
std::vector mColumns;
LLRect mRectangle;
};
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index e927142275..da152d96b6 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1705,11 +1705,14 @@ void LLTextBase::reflow()
{
// find first element whose end comes after start_index
line_list_t::iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), start_index, line_end_compare());
- line_start_index = iter->mDocIndexStart;
- line_count = iter->mLineNum;
- cur_top = iter->mRect.mTop;
- getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset);
- mLineInfoList.erase(iter, mLineInfoList.end());
+ if (iter != mLineInfoList.end())
+ {
+ line_start_index = iter->mDocIndexStart;
+ line_count = iter->mLineNum;
+ cur_top = iter->mRect.mTop;
+ getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset);
+ mLineInfoList.erase(iter, mLineInfoList.end());
+ }
}
S32 line_height = 0;
diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index ee5873885b..dcce2aa1fd 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -1177,7 +1177,8 @@ LLToolBarButton* LLToolBar::createButton(const LLCommandId& id)
else
{
button->setFunctionName(commandp->executeFunctionName());
- LL_DEBUGS("UIUsage") << "button function name b -> " << commandp->executeFunctionName() << LL_ENDL; // Check enabled state of button before executing!
+ LL_DEBUGS("UIUsage") << "button function name b -> " << commandp->executeFunctionName() << LL_ENDL;
+ // Check enabled state of button before executing!
//button->setCommitCallback(executeParam);
LLUICtrl::commit_callback_t execute_func = initCommitCallback(executeParam);
button->setCommitCallback(boost::bind(&LLToolBarButton::callIfEnabled, button, execute_func, _1, _2));
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 493060886c..b407f4a3df 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -197,6 +197,7 @@ mHelpImpl(NULL)
reg.add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleInstance, _2, LLSD()));
reg.add("Floater.ToggleOrBringToFront", boost::bind(&LLFloaterReg::toggleInstanceOrBringToFront, _2, LLSD()));
reg.add("Floater.Show", boost::bind(&LLFloaterReg::showInstance, _2, LLSD(), FALSE));
+ reg.add("Floater.ShowOrBringToFront", boost::bind(&LLFloaterReg::showInstanceOrBringToFront, _2, LLSD()));
reg.add("Floater.Hide", boost::bind(&LLFloaterReg::hideInstance, _2, LLSD()));
// Button initialization callback for toggle buttons
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt
index bb003a77e3..53e4df3825 100644
--- a/indra/llwindow/CMakeLists.txt
+++ b/indra/llwindow/CMakeLists.txt
@@ -77,7 +77,8 @@ if (LINUX)
${LLXML_LIBRARIES}
${UI_LIBRARIES} # for GTK
${SDL_LIBRARY}
- fontconfig # For FCInit and other FC* functions.
+ libfontconfig.a # For FCInit and other FC* functions.
+ libfreetype.a
)
list(APPEND viewer_SOURCE_FILES
diff --git a/indra/llwindow/llcursortypes.cpp b/indra/llwindow/llcursortypes.cpp
index 86f4d898bc..c5db67532d 100644
--- a/indra/llwindow/llcursortypes.cpp
+++ b/indra/llwindow/llcursortypes.cpp
@@ -42,6 +42,7 @@ ECursorType getCursorFromString(const std::string& cursor_string)
cursor_string_table["UI_CURSOR_SIZENESW"] = UI_CURSOR_SIZENESW;
cursor_string_table["UI_CURSOR_SIZEWE"] = UI_CURSOR_SIZEWE;
cursor_string_table["UI_CURSOR_SIZENS"] = UI_CURSOR_SIZENS;
+ cursor_string_table["UI_CURSOR_SIZEALL"] = UI_CURSOR_SIZEALL;
cursor_string_table["UI_CURSOR_NO"] = UI_CURSOR_NO;
cursor_string_table["UI_CURSOR_WORKING"] = UI_CURSOR_WORKING;
cursor_string_table["UI_CURSOR_TOOLGRAB"] = UI_CURSOR_TOOLGRAB;
@@ -61,6 +62,7 @@ ECursorType getCursorFromString(const std::string& cursor_string)
cursor_string_table["UI_CURSOR_TOOLCAMERA"] = UI_CURSOR_TOOLCAMERA;
cursor_string_table["UI_CURSOR_TOOLPAN"] = UI_CURSOR_TOOLPAN;
cursor_string_table["UI_CURSOR_TOOLZOOMIN"] = UI_CURSOR_TOOLZOOMIN;
+ cursor_string_table["UI_CURSOR_TOOLZOOMOUT"] = UI_CURSOR_TOOLZOOMOUT;
cursor_string_table["UI_CURSOR_TOOLPICKOBJECT3"] = UI_CURSOR_TOOLPICKOBJECT3;
cursor_string_table["UI_CURSOR_TOOLPLAY"] = UI_CURSOR_TOOLPLAY;
cursor_string_table["UI_CURSOR_TOOLPAUSE"] = UI_CURSOR_TOOLPAUSE;
diff --git a/indra/llwindow/llcursortypes.h b/indra/llwindow/llcursortypes.h
index 73f3fe6cdf..10bd38d448 100644
--- a/indra/llwindow/llcursortypes.h
+++ b/indra/llwindow/llcursortypes.h
@@ -38,6 +38,7 @@ enum ECursorType {
UI_CURSOR_SIZENESW,
UI_CURSOR_SIZEWE,
UI_CURSOR_SIZENS,
+ UI_CURSOR_SIZEALL,
UI_CURSOR_NO,
UI_CURSOR_WORKING,
UI_CURSOR_TOOLGRAB,
@@ -57,6 +58,7 @@ enum ECursorType {
UI_CURSOR_TOOLCAMERA,
UI_CURSOR_TOOLPAN,
UI_CURSOR_TOOLZOOMIN,
+ UI_CURSOR_TOOLZOOMOUT,
UI_CURSOR_TOOLPICKOBJECT3,
UI_CURSOR_TOOLPLAY,
UI_CURSOR_TOOLPAUSE,
diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm
index 7d54bdaee2..41db6ae98e 100644
--- a/indra/llwindow/llwindowmacosx-objc.mm
+++ b/indra/llwindow/llwindowmacosx-objc.mm
@@ -106,13 +106,13 @@ const unsigned short *copyFromPBoard()
CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
+
// extra retain on the NSCursor since we want it to live for the lifetime of the app.
NSCursor *cursor =
[[[NSCursor alloc]
initWithImage:
[[[NSImage alloc] initWithContentsOfFile:
- [NSString stringWithFormat:@"%s", fullpath]
+ [NSString stringWithUTF8String:fullpath]
]autorelease]
hotSpot:NSMakePoint(hotspotX, hotspotY)
]retain];
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index e0ddb6b07b..6c85f2c21b 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -1443,6 +1443,7 @@ const char* cursorIDToName(int id)
case UI_CURSOR_SIZENESW: return "UI_CURSOR_SIZENESW";
case UI_CURSOR_SIZEWE: return "UI_CURSOR_SIZEWE";
case UI_CURSOR_SIZENS: return "UI_CURSOR_SIZENS";
+ case UI_CURSOR_SIZEALL: return "UI_CURSOR_SIZEALL";
case UI_CURSOR_NO: return "UI_CURSOR_NO";
case UI_CURSOR_WORKING: return "UI_CURSOR_WORKING";
case UI_CURSOR_TOOLGRAB: return "UI_CURSOR_TOOLGRAB";
@@ -1462,6 +1463,7 @@ const char* cursorIDToName(int id)
case UI_CURSOR_TOOLCAMERA: return "UI_CURSOR_TOOLCAMERA";
case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN";
case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN";
+ case UI_CURSOR_TOOLZOOMOUT: return "UI_CURSOR_TOOLZOOMOUT";
case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3";
case UI_CURSOR_TOOLPLAY: return "UI_CURSOR_TOOLPLAY";
case UI_CURSOR_TOOLPAUSE: return "UI_CURSOR_TOOLPAUSE";
@@ -1640,6 +1642,7 @@ void LLWindowMacOSX::initCursors(BOOL useLegacyCursors)
initPixmapCursor(UI_CURSOR_TOOLCAMERA, 7, 6);
initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6);
initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6);
+ initPixmapCursor(UI_CURSOR_TOOLZOOMOUT, 7, 6);
initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1);
initPixmapCursor(UI_CURSOR_TOOLPLAY, 1, 1);
initPixmapCursor(UI_CURSOR_TOOLPAUSE, 1, 1);
@@ -1674,6 +1677,7 @@ void LLWindowMacOSX::initCursors(BOOL useLegacyCursors)
initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10);
initPixmapCursor(UI_CURSOR_SIZEWE, 10, 10);
initPixmapCursor(UI_CURSOR_SIZENS, 10, 10);
+ initPixmapCursor(UI_CURSOR_SIZEALL, 10, 10);
}
@@ -1708,7 +1712,7 @@ void LLWindowMacOSX::hideCursor()
void LLWindowMacOSX::showCursor()
{
- if(mCursorHidden)
+ if(mCursorHidden || !isCGCursorVisible())
{
// LL_INFOS() << "showCursor: showing" << LL_ENDL;
mCursorHidden = FALSE;
diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp
index b84d74a244..e0cd0bfb46 100644
--- a/indra/llwindow/llwindowsdl.cpp
+++ b/indra/llwindow/llwindowsdl.cpp
@@ -43,10 +43,15 @@
#if LL_GTK
extern "C" {
# include "gtk/gtk.h"
+#error "Direct use of GTK is deprecated"
}
#include
#endif // LL_GTK
+#ifdef LL_GLIB
+#include
+#endif
+
extern "C" {
# include "fontconfig/fontconfig.h"
}
@@ -186,6 +191,248 @@ Display* LLWindowSDL::get_SDL_Display(void)
}
#endif // LL_X11
+#if LL_X11
+
+// Clipboard handing via native X11, base on the implementation in Cool VL by Henri Beauchamp
+
+namespace
+{
+ std::array gSupportedAtoms;
+
+ Atom XA_CLIPBOARD;
+ Atom XA_TARGETS;
+ Atom PVT_PASTE_BUFFER;
+ long const MAX_PASTE_BUFFER_SIZE = 16383;
+
+ void filterSelectionRequest( XEvent aEvent )
+ {
+ auto *display = LLWindowSDL::getSDLDisplay();
+ auto &request = aEvent.xselectionrequest;
+
+ XSelectionEvent reply { SelectionNotify, aEvent.xany.serial, aEvent.xany.send_event, display,
+ request.requestor, request.selection, request.target,
+ request.property,request.time };
+
+ if (request.target == XA_TARGETS)
+ {
+ XChangeProperty(display, request.requestor, request.property,
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) &gSupportedAtoms.front(), gSupportedAtoms.size());
+ }
+ else if (std::find(gSupportedAtoms.begin(), gSupportedAtoms.end(), request.target) !=
+ gSupportedAtoms.end())
+ {
+ std::string utf8;
+ if (request.selection == XA_PRIMARY)
+ utf8 = wstring_to_utf8str(gWindowImplementation->getPrimaryText());
+ else
+ utf8 = wstring_to_utf8str(gWindowImplementation->getSecondaryText());
+
+ XChangeProperty(display, request.requestor, request.property,
+ request.target, 8, PropModeReplace,
+ (unsigned char *) utf8.c_str(), utf8.length());
+ }
+ else if (request.selection == XA_CLIPBOARD)
+ {
+ // Did not have what they wanted, so no property set
+ reply.property = None;
+ }
+ else
+ return;
+
+ XSendEvent(request.display, request.requestor, False, NoEventMask, (XEvent *) &reply);
+ XSync(display, False);
+ }
+
+ void filterSelectionClearRequest( XEvent aEvent )
+ {
+ auto &request = aEvent.xselectionrequest;
+ if (request.selection == XA_PRIMARY)
+ gWindowImplementation->clearPrimaryText();
+ else if (request.selection == XA_CLIPBOARD)
+ gWindowImplementation->clearSecondaryText();
+ }
+
+ int x11_clipboard_filter(const SDL_Event *evt)
+ {
+ Display *display = LLWindowSDL::getSDLDisplay();
+ if (!display)
+ return 1;
+
+ if (evt->type != SDL_SYSWMEVENT)
+ return 1;
+
+ auto xevent = evt->syswm.msg->event.xevent;
+
+ if (xevent.type == SelectionRequest)
+ filterSelectionRequest( xevent );
+ else if (xevent.type == SelectionClear)
+ filterSelectionClearRequest( xevent );
+ return 1;
+ }
+
+ bool grab_property(Display* display, Window window, Atom selection, Atom target)
+ {
+ if( !display )
+ return false;
+
+ maybe_lock_display();
+
+ XDeleteProperty(display, window, PVT_PASTE_BUFFER);
+ XFlush(display);
+
+ XConvertSelection(display, selection, target, PVT_PASTE_BUFFER, window, CurrentTime);
+
+ // Unlock the connection so that the SDL event loop may function
+ maybe_unlock_display();
+
+ const auto start{ SDL_GetTicks() };
+ const auto end{ start + 1000 };
+
+ XEvent xevent {};
+ bool response = false;
+
+ do
+ {
+ SDL_Event event {};
+
+ // Wait for an event
+ SDL_WaitEvent(&event);
+
+ // If the event is a window manager event
+ if (event.type == SDL_SYSWMEVENT)
+ {
+ xevent = event.syswm.msg->event.xevent;
+
+ if (xevent.type == SelectionNotify && xevent.xselection.requestor == window)
+ response = true;
+ }
+ } while (!response && SDL_GetTicks() < end );
+
+ return response && xevent.xselection.property != None;
+ }
+}
+
+void LLWindowSDL::initialiseX11Clipboard()
+{
+ if (!mSDL_Display)
+ return;
+
+ SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
+ SDL_SetEventFilter(x11_clipboard_filter);
+
+ maybe_lock_display();
+
+ XA_CLIPBOARD = XInternAtom(mSDL_Display, "CLIPBOARD", False);
+
+ gSupportedAtoms[0] = XA_STRING;
+
+ gSupportedAtoms[1] = XInternAtom(mSDL_Display, "COMPOUND_TEXT", False);
+ gSupportedAtoms[2] = XInternAtom(mSDL_Display, "UTF8_STRING", False);
+
+ // TARGETS atom
+ XA_TARGETS = XInternAtom(mSDL_Display, "TARGETS", False);
+
+ // SL_PASTE_BUFFER atom
+ PVT_PASTE_BUFFER = XInternAtom(mSDL_Display, "FS_PASTE_BUFFER", False);
+
+ maybe_unlock_display();
+}
+
+bool LLWindowSDL::getSelectionText( Atom aSelection, Atom aType, LLWString &text )
+{
+ if( !mSDL_Display )
+ return false;
+
+ if( !grab_property(mSDL_Display, mSDL_XWindowID, aSelection,aType ) )
+ return false;
+
+ maybe_lock_display();
+
+ Atom type;
+ int format{};
+ unsigned long len{},remaining {};
+ unsigned char* data = nullptr;
+ int res = XGetWindowProperty(mSDL_Display, mSDL_XWindowID,
+ PVT_PASTE_BUFFER, 0, MAX_PASTE_BUFFER_SIZE, False,
+ AnyPropertyType, &type, &format, &len,
+ &remaining, &data);
+ if (data && len)
+ {
+ text = LLWString(
+ utf8str_to_wstring(reinterpret_cast< char const *>( data ) )
+ );
+ XFree(data);
+ }
+
+ maybe_unlock_display();
+ return res == Success;
+}
+
+bool LLWindowSDL::getSelectionText(Atom selection, LLWString& text)
+{
+ if (!mSDL_Display)
+ return false;
+
+ maybe_lock_display();
+
+ Window owner = XGetSelectionOwner(mSDL_Display, selection);
+ if (owner == None)
+ {
+ if (selection == XA_PRIMARY)
+ {
+ owner = DefaultRootWindow(mSDL_Display);
+ selection = XA_CUT_BUFFER0;
+ }
+ else
+ {
+ maybe_unlock_display();
+ return false;
+ }
+ }
+
+ maybe_unlock_display();
+
+ for( Atom atom : gSupportedAtoms )
+ {
+ if(getSelectionText(selection, atom, text ) )
+ return true;
+ }
+
+ return false;
+}
+
+bool LLWindowSDL::setSelectionText(Atom selection, const LLWString& text)
+{
+ maybe_lock_display();
+
+ if (selection == XA_PRIMARY)
+ {
+ std::string utf8 = wstring_to_utf8str(text);
+ XStoreBytes(mSDL_Display, utf8.c_str(), utf8.length() + 1);
+ mPrimaryClipboard = text;
+ }
+ else
+ mSecondaryClipboard = text;
+
+ XSetSelectionOwner(mSDL_Display, selection, mSDL_XWindowID, CurrentTime);
+
+ auto owner = XGetSelectionOwner(mSDL_Display, selection);
+
+ maybe_unlock_display();
+
+ return owner == mSDL_XWindowID;
+}
+
+Display* LLWindowSDL::getSDLDisplay()
+{
+ if (gWindowImplementation)
+ return gWindowImplementation->mSDL_Display;
+ return nullptr;
+}
+
+#endif
+
LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks,
const std::string& title, S32 x, S32 y, S32 width,
@@ -253,6 +500,7 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks,
#if LL_X11
mFlashing = FALSE;
+ initialiseX11Clipboard();
#endif // LL_X11
mKeyScanCode = 0;
@@ -1356,33 +1604,34 @@ BOOL LLWindowSDL::copyTextToPrimary(const LLWString &text)
#else
BOOL LLWindowSDL::isClipboardTextAvailable()
-{
- return FALSE; // unsupported
+{
+ return mSDL_Display && XGetSelectionOwner(mSDL_Display, XA_CLIPBOARD) != None;
}
BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst)
{
- return FALSE; // unsupported
+ return getSelectionText(XA_CLIPBOARD, dst);
}
BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s)
{
- return FALSE; // unsupported
+ return setSelectionText(XA_CLIPBOARD, s);
}
BOOL LLWindowSDL::isPrimaryTextAvailable()
{
- return FALSE; // unsupported
+ LLWString text;
+ return getSelectionText(XA_PRIMARY, text) && !text.empty();
}
BOOL LLWindowSDL::pasteTextFromPrimary(LLWString &dst)
{
- return FALSE; // unsupported
+ return getSelectionText(XA_PRIMARY, dst);
}
BOOL LLWindowSDL::copyTextToPrimary(const LLWString &s)
{
- return FALSE; // unsupported
+ return setSelectionText(XA_PRIMARY, s);
}
#endif // LL_GTK
@@ -1747,7 +1996,18 @@ void LLWindowSDL::processMiscNativeEvents()
setlocale(LC_ALL, saved_locale.c_str() );
}
#endif // LL_GTK
-
+#if LL_GLIB
+ // Pump until we've nothing left to do or passed 1/15th of a
+ // second pumping for this frame.
+ static LLTimer pump_timer;
+ pump_timer.reset();
+ pump_timer.setTimerExpirySec(1.0f / 15.0f);
+ do
+ {
+ g_main_context_iteration(g_main_context_default(), FALSE);
+ } while( g_main_context_pending(g_main_context_default()) && !pump_timer.hasExpired());
+#endif
+
// hack - doesn't belong here - but this is just for debugging
if (getenv("LL_DEBUG_BLOAT"))
{
@@ -2109,6 +2369,7 @@ void LLWindowSDL::initCursors(BOOL useLegacyCursors) // Legacy cursor se
mSDLCursors[UI_CURSOR_SIZENESW] = makeSDLCursorFromBMP("sizenesw.BMP",17,17);
mSDLCursors[UI_CURSOR_SIZEWE] = makeSDLCursorFromBMP("sizewe.BMP",16,14);
mSDLCursors[UI_CURSOR_SIZENS] = makeSDLCursorFromBMP("sizens.BMP",17,16);
+ mSDLCursors[UI_CURSOR_SIZEALL] = makeSDLCursorFromBMP("sizeall.BMP", 17, 17);
mSDLCursors[UI_CURSOR_NO] = makeSDLCursorFromBMP("llno.BMP",8,8);
mSDLCursors[UI_CURSOR_WORKING] = makeSDLCursorFromBMP("working.BMP",12,15);
mSDLCursors[UI_CURSOR_TOOLGRAB] = makeSDLCursorFromBMP("lltoolgrab.BMP",2,13);
@@ -2128,6 +2389,7 @@ void LLWindowSDL::initCursors(BOOL useLegacyCursors) // Legacy cursor se
mSDLCursors[UI_CURSOR_TOOLCAMERA] = makeSDLCursorFromBMP("lltoolcamera.BMP",7,5);
mSDLCursors[UI_CURSOR_TOOLPAN] = makeSDLCursorFromBMP("lltoolpan.BMP",7,5);
mSDLCursors[UI_CURSOR_TOOLZOOMIN] = makeSDLCursorFromBMP("lltoolzoomin.BMP",7,5);
+ mSDLCursors[UI_CURSOR_TOOLZOOMOUT] = makeSDLCursorFromBMP("lltoolzoomout.BMP", 7, 5);
mSDLCursors[UI_CURSOR_TOOLPICKOBJECT3] = makeSDLCursorFromBMP("toolpickobject3.BMP",0,0);
mSDLCursors[UI_CURSOR_TOOLPLAY] = makeSDLCursorFromBMP("toolplay.BMP",0,0);
mSDLCursors[UI_CURSOR_TOOLPAUSE] = makeSDLCursorFromBMP("toolpause.BMP",0,0);
@@ -2396,39 +2658,6 @@ static void color_changed_callback(GtkWidget *widget,
gtk_color_selection_get_current_color(colorsel, colorp);
}
-
-/*
- 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;
- result[ "sdl_sym" ] = (S32)mSDLSym; // Store the SDL Keysym too.
- return result;
-}
-
-
BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b)
{
BOOL rtn = FALSE;
@@ -2513,6 +2742,37 @@ BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b)
}
#endif // LL_GTK
+/*
+ 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;
+ result[ "sdl_sym" ] = (S32)mSDLSym; // Store the SDL Keysym too.
+ return result;
+}
+
#if LL_LINUX
// extracted from spawnWebBrowser for clarity and to eliminate
// compiler confusion regarding close(int fd) vs. LLWindow::close()
diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h
index de0ee173ec..a0ca9839a5 100644
--- a/indra/llwindow/llwindowsdl.h
+++ b/indra/llwindow/llwindowsdl.h
@@ -220,6 +220,24 @@ private:
U32 mSDLSym; // Store the SDL Keysym too.
BOOL mUseLegacyCursors; // Legacy cursor setting from main program
+
+public:
+#if LL_X11
+ static Display* getSDLDisplay();
+ LLWString const& getPrimaryText() const { return mPrimaryClipboard; }
+ LLWString const& getSecondaryText() const { return mSecondaryClipboard; }
+ void clearPrimaryText() { mPrimaryClipboard.clear(); }
+ void clearSecondaryText() { mSecondaryClipboard.clear(); }
+private:
+ void initialiseX11Clipboard();
+
+ bool getSelectionText(Atom selection, LLWString& text);
+ bool getSelectionText( Atom selection, Atom type, LLWString &text );
+
+ bool setSelectionText(Atom selection, const LLWString& text);
+#endif
+ LLWString mPrimaryClipboard;
+ LLWString mSecondaryClipboard;
};
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index d2d24bb730..005d5e25ac 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1918,8 +1918,9 @@ void LLWindowWin32::initCursors(BOOL useLegacyCursors) // Legacy cursor
mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS);
mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE);
mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW);
- mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE);
- mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS);
+ mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE);
+ mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS);
+ mCursor[ UI_CURSOR_SIZEALL ] = LoadCursor(NULL, IDC_SIZEALL);
mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO);
mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING);
@@ -1941,6 +1942,7 @@ void LLWindowWin32::initCursors(BOOL useLegacyCursors) // Legacy cursor
mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA"));
mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN"));
mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN"));
+ mCursor[ UI_CURSOR_TOOLZOOMOUT ] = LoadCursor(module, TEXT("TOOLZOOMOUT"));
mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3"));
mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE"));
/* Legacy cursor setting from main program
diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt
index 32e440a829..cde480a46d 100644
--- a/indra/media_plugins/CMakeLists.txt
+++ b/indra/media_plugins/CMakeLists.txt
@@ -2,10 +2,9 @@
add_subdirectory(base)
if (LINUX)
-# add_subdirectory(gstreamer010)
- add_subdirectory(cef)
- add_subdirectory(libvlc)
- #add_subdirectory(example)
+ add_subdirectory(gstreamer10)
+ add_subdirectory(cef)
+ #add_subdirectory(libvlc)
endif (LINUX)
if (DARWIN)
diff --git a/indra/media_plugins/base/CMakeLists.txt b/indra/media_plugins/base/CMakeLists.txt
index 7f2b82ffdd..197c41bc20 100644
--- a/indra/media_plugins/base/CMakeLists.txt
+++ b/indra/media_plugins/base/CMakeLists.txt
@@ -49,4 +49,3 @@ set(media_plugin_base_HEADER_FILES
add_library(media_plugin_base
${media_plugin_base_SOURCE_FILES}
)
-
diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt
index a846c04626..3f85cfc6a4 100644
--- a/indra/media_plugins/cef/CMakeLists.txt
+++ b/indra/media_plugins/cef/CMakeLists.txt
@@ -58,7 +58,8 @@ set (media_plugin_cef_LINK_LIBRARIES
if (LINUX)
# message(FATAL_ERROR "CEF plugin has been enabled for a Linux compile.\n"
# " Please create a volume_catcher implementation for this platform.")
- list(APPEND media_plugin_cef_SOURCE_FILES dummy_volume_catcher.cpp)
+
+ list(APPEND media_plugin_cef_SOURCE_FILES ${LINUX_VOLUME_CATCHER})
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--build-id -Wl,-rpath,'$ORIGIN:$ORIGIN/../../lib'")
elseif (DARWIN)
list(APPEND media_plugin_cef_SOURCE_FILES mac_volume_catcher_null.cpp)
diff --git a/indra/media_plugins/cef/linux_volume_catcher.cpp b/indra/media_plugins/cef/linux_volume_catcher.cpp
index 91be3a89e9..fdea6fb15f 100755
--- a/indra/media_plugins/cef/linux_volume_catcher.cpp
+++ b/indra/media_plugins/cef/linux_volume_catcher.cpp
@@ -53,6 +53,7 @@ extern "C" {
#include "apr_dso.h"
}
+
////////////////////////////////////////////////////
#define DEBUGMSG(...) do {} while(0)
@@ -81,7 +82,7 @@ bool grab_pa_syms(std::string pulse_dso_name)
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)
+#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) { if (REQUIRED) sym_error = true;} } while(0);
//attempt to load the shared library
apr_pool_create(&sSymPADSOMemoryPool, NULL);
@@ -216,17 +217,16 @@ void VolumeCatcherImpl::init()
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");
@@ -236,6 +236,7 @@ void VolumeCatcherImpl::init()
// plain old pa_context_new() is broken!
mPAContext = llpa_context_new_with_proplist(api, NULL, proplist);
+
llpa_proplist_free(proplist);
}
}
@@ -350,6 +351,51 @@ void VolumeCatcherImpl::update_index_volume(U32 index, F32 volume)
}
}
+pid_t getParentPid( pid_t aPid )
+{
+ std::stringstream strm;
+ strm << "/proc/" << aPid << "/status";
+ std::ifstream in{ strm.str() };
+
+ if( !in.is_open() )
+ return 0;
+
+ pid_t res {0};
+ while( !in.eof() && res == 0 )
+ {
+ std::string line;
+ line.resize( 1024, 0 );
+ in.getline( &line[0], line.length() );
+
+ auto i = line.find( "PPid:" );
+
+ if( i == std::string::npos )
+ continue;
+
+ char const *pIn = line.c_str() + 5; // Skip over pid;
+ while( *pIn != 0 && isspace( *pIn ) )
+ ++pIn;
+
+ if( *pIn )
+ res = atoll( pIn );
+ }
+ return res;
+}
+
+
+bool isPluginPid( pid_t aPid )
+{
+ auto myPid = getpid();
+
+ do
+ {
+ if( aPid == myPid )
+ return true;
+ aPid = getParentPid( aPid );
+ } while( aPid > 1 );
+
+ return false;
+}
void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata)
{
@@ -360,11 +406,10 @@ void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info
{
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?
+
+ if (isPluginPid( sinkpid )) // does the discovered sinkinput belong to this process?
{
- bool is_new = (impl->mSinkInputIndices.find(sii->index) ==
- impl->mSinkInputIndices.end());
+ bool is_new = (impl->mSinkInputIndices.find(sii->index) == impl->mSinkInputIndices.end());
impl->mSinkInputIndices.insert(sii->index);
impl->mSinkInputNumChannels[sii->index] = sii->channel_map.channels;
@@ -387,32 +432,31 @@ void callback_subscription_alert(pa_context *context, pa_subscription_event_type
VolumeCatcherImpl *impl = dynamic_cast((VolumeCatcherImpl*)userdata);
llassert(impl);
- switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
+ 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)))
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
{
- llpa_operation_unref(op);
+ // forget this sinkinput, if we were caring about it
+ impl->mSinkInputIndices.erase(index);
+ impl->mSinkInputNumChannels.erase(index);
}
- }
- else
- {
- // property change on this sinkinput - we don't care.
- }
- break;
+ 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:;
+ default:;
}
}
diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp
index 7dbceba2d8..ca185049ce 100644
--- a/indra/media_plugins/cef/media_plugin_cef.cpp
+++ b/indra/media_plugins/cef/media_plugin_cef.cpp
@@ -87,6 +87,9 @@ private:
bool mCookiesEnabled;
bool mPluginsEnabled;
bool mJavascriptEnabled;
+ bool mProxyEnabled;
+ std::string mProxyHost;
+ int mProxyPort;
bool mDisableGPU;
bool mDisableNetworkService;
bool mUseMockKeyChain;
@@ -124,6 +127,9 @@ MediaPluginBase(host_send_func, host_user_data)
mCookiesEnabled = true;
mPluginsEnabled = false;
mJavascriptEnabled = true;
+ mProxyEnabled = false;
+ mProxyHost = "";
+ mProxyPort = 0;
mDisableGPU = false;
mDisableNetworkService = true;
mUseMockKeyChain = true;
@@ -397,21 +403,86 @@ void MediaPluginCEF::onCursorChangedCallback(dullahan::ECursorType type)
switch (type)
{
- case dullahan::CT_POINTER:
- name = "arrow";
- break;
+ case dullahan::CT_POINTER:
+ name = "UI_CURSOR_ARROW";
+ break;
+ case dullahan::CT_CROSS:
+ name = "UI_CURSOR_CROSS";
+ break;
+ case dullahan::CT_HAND:
+ name = "UI_CURSOR_HAND";
+ break;
case dullahan::CT_IBEAM:
- name = "ibeam";
- break;
- case dullahan::CT_NORTHSOUTHRESIZE:
- name = "splitv";
- break;
- case dullahan::CT_EASTWESTRESIZE:
- name = "splith";
- break;
- case dullahan::CT_HAND:
- name = "hand";
+ name = "UI_CURSOR_IBEAM";
break;
+ case dullahan::CT_WAIT:
+ name = "UI_CURSOR_WAIT";
+ break;
+ //case dullahan::CT_HELP:
+ case dullahan::CT_ROWRESIZE:
+ case dullahan::CT_NORTHRESIZE:
+ case dullahan::CT_SOUTHRESIZE:
+ case dullahan::CT_NORTHSOUTHRESIZE:
+ name = "UI_CURSOR_SIZENS";
+ break;
+ case dullahan::CT_COLUMNRESIZE:
+ case dullahan::CT_EASTRESIZE:
+ case dullahan::CT_WESTRESIZE:
+ case dullahan::CT_EASTWESTRESIZE:
+ name = "UI_CURSOR_SIZEWE";
+ break;
+ case dullahan::CT_NORTHEASTRESIZE:
+ case dullahan::CT_SOUTHWESTRESIZE:
+ case dullahan::CT_NORTHEASTSOUTHWESTRESIZE:
+ name = "UI_CURSOR_SIZENESW";
+ break;
+ case dullahan::CT_SOUTHEASTRESIZE:
+ case dullahan::CT_NORTHWESTRESIZE:
+ case dullahan::CT_NORTHWESTSOUTHEASTRESIZE:
+ name = "UI_CURSOR_SIZENWSE";
+ break;
+ case dullahan::CT_MOVE:
+ name = "UI_CURSOR_SIZEALL";
+ break;
+ //case dullahan::CT_MIDDLEPANNING:
+ //case dullahan::CT_EASTPANNING:
+ //case dullahan::CT_NORTHPANNING:
+ //case dullahan::CT_NORTHEASTPANNING:
+ //case dullahan::CT_NORTHWESTPANNING:
+ //case dullahan::CT_SOUTHPANNING:
+ //case dullahan::CT_SOUTHEASTPANNING:
+ //case dullahan::CT_SOUTHWESTPANNING:
+ //case dullahan::CT_WESTPANNING:
+ //case dullahan::CT_VERTICALTEXT:
+ //case dullahan::CT_CELL:
+ //case dullahan::CT_CONTEXTMENU:
+ case dullahan::CT_ALIAS:
+ name = "UI_CURSOR_TOOLMEDIAOPEN";
+ break;
+ case dullahan::CT_PROGRESS:
+ name = "UI_CURSOR_WORKING";
+ break;
+ case dullahan::CT_COPY:
+ name = "UI_CURSOR_ARROWCOPY";
+ break;
+ case dullahan::CT_NONE:
+ name = "UI_CURSOR_NO";
+ break;
+ case dullahan::CT_NODROP:
+ case dullahan::CT_NOTALLOWED:
+ name = "UI_CURSOR_NOLOCKED";
+ break;
+ case dullahan::CT_ZOOMIN:
+ name = "UI_CURSOR_TOOLZOOMIN";
+ break;
+ case dullahan::CT_ZOOMOUT:
+ name = "UI_CURSOR_TOOLZOOMOUT";
+ break;
+ case dullahan::CT_GRAB:
+ name = "UI_CURSOR_TOOLGRAB";
+ break;
+ //case dullahan::CT_GRABING:
+ //case dullahan::CT_CUSTOM:
default:
LL_WARNS() << "Unknown cursor ID: " << (int)type << LL_ENDL;
@@ -518,50 +589,60 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
}
else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
{
- if (message_name == "init")
- {
- // event callbacks from Dullahan
- mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
- mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1));
- mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
- mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1));
- mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1));
- mCEFLib->setOnTooltipCallback(std::bind(&MediaPluginCEF::onTooltipCallback, this, std::placeholders::_1));
- mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this));
- mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1, std::placeholders::_2));
- mCEFLib->setOnLoadErrorCallback(std::bind(&MediaPluginCEF::onLoadError, this, std::placeholders::_1, std::placeholders::_2));
- mCEFLib->setOnAddressChangeCallback(std::bind(&MediaPluginCEF::onAddressChangeCallback, this, std::placeholders::_1));
- mCEFLib->setOnOpenPopupCallback(std::bind(&MediaPluginCEF::onOpenPopupCallback, this, std::placeholders::_1, std::placeholders::_2));
- mCEFLib->setOnHTTPAuthCallback(std::bind(&MediaPluginCEF::onHTTPAuthCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
- mCEFLib->setOnFileDialogCallback(std::bind(&MediaPluginCEF::onFileDialog, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
- mCEFLib->setOnCursorChangedCallback(std::bind(&MediaPluginCEF::onCursorChangedCallback, this, std::placeholders::_1));
- mCEFLib->setOnRequestExitCallback(std::bind(&MediaPluginCEF::onRequestExitCallback, this));
- mCEFLib->setOnJSDialogCallback(std::bind(&MediaPluginCEF::onJSDialogCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
- mCEFLib->setOnJSBeforeUnloadCallback(std::bind(&MediaPluginCEF::onJSBeforeUnloadCallback, this));
-
- dullahan::dullahan_settings settings;
+ if (message_name == "init")
+ {
+ // event callbacks from Dullahan
+ mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
+ mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1));
+ mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+ mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1));
+ mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1));
+ mCEFLib->setOnTooltipCallback(std::bind(&MediaPluginCEF::onTooltipCallback, this, std::placeholders::_1));
+ mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this));
+ mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1, std::placeholders::_2));
+ mCEFLib->setOnLoadErrorCallback(std::bind(&MediaPluginCEF::onLoadError, this, std::placeholders::_1, std::placeholders::_2));
+ mCEFLib->setOnAddressChangeCallback(std::bind(&MediaPluginCEF::onAddressChangeCallback, this, std::placeholders::_1));
+ mCEFLib->setOnOpenPopupCallback(std::bind(&MediaPluginCEF::onOpenPopupCallback, this, std::placeholders::_1, std::placeholders::_2));
+ mCEFLib->setOnHTTPAuthCallback(std::bind(&MediaPluginCEF::onHTTPAuthCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
+ mCEFLib->setOnFileDialogCallback(std::bind(&MediaPluginCEF::onFileDialog, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
+ mCEFLib->setOnCursorChangedCallback(std::bind(&MediaPluginCEF::onCursorChangedCallback, this, std::placeholders::_1));
+ mCEFLib->setOnRequestExitCallback(std::bind(&MediaPluginCEF::onRequestExitCallback, this));
+ mCEFLib->setOnJSDialogCallback(std::bind(&MediaPluginCEF::onJSDialogCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+ mCEFLib->setOnJSBeforeUnloadCallback(std::bind(&MediaPluginCEF::onJSBeforeUnloadCallback, this));
+
+ dullahan::dullahan_settings settings;
#if LL_WINDOWS
- // As of CEF version 83+, for Windows versions, we need to tell CEF
- // where the host helper process is since this DLL is not in the same
- // dir as the executable that loaded it (SLPlugin.exe). The code in
- // Dullahan that tried to figure out the location automatically uses
- // the location of the exe which isn't helpful so we tell it explicitly.
- char cur_dir_str[MAX_PATH];
- GetCurrentDirectoryA(MAX_PATH, cur_dir_str);
- settings.host_process_path = std::string(cur_dir_str);
+ // As of CEF version 83+, for Windows versions, we need to tell CEF
+ // where the host helper process is since this DLL is not in the same
+ // dir as the executable that loaded it (SLPlugin.exe). The code in
+ // Dullahan that tried to figure out the location automatically uses
+ // the location of the exe which isn't helpful so we tell it explicitly.
+ char cur_dir_str[MAX_PATH];
+ GetCurrentDirectoryA(MAX_PATH, cur_dir_str);
+ settings.host_process_path = std::string(cur_dir_str);
#endif
- settings.accept_language_list = mHostLanguage;
+ settings.accept_language_list = mHostLanguage;
- // SL-15560: Product team overruled my change to set the default
- // embedded background color to match the floater background
- // and set it to white
- settings.background_color = 0xffffffff; // white
+ // SL-15560: Product team overruled my change to set the default
+ // embedded background color to match the floater background
+ // and set it to white
+ settings.background_color = 0xffffffff; // white
- settings.cache_enabled = true;
- settings.root_cache_path = mRootCachePath;
- settings.cache_path = mCachePath;
- settings.context_cache_path = mContextCachePath;
- settings.cookies_enabled = mCookiesEnabled;
+ settings.cache_enabled = true;
+ settings.root_cache_path = mRootCachePath;
+ settings.cache_path = mCachePath;
+ settings.context_cache_path = mContextCachePath;
+ settings.cookies_enabled = mCookiesEnabled;
+
+#ifndef LL_LINUX
+ // configure proxy argument if enabled and valid
+ if (mProxyEnabled && mProxyHost.length())
+ {
+ std::ostringstream proxy_url;
+ proxy_url << mProxyHost << ":" << mProxyPort;
+ settings.proxy_host_port = proxy_url.str();
+ }
+#endif
settings.disable_gpu = mDisableGPU;
#if LL_DARWIN
settings.disable_network_service = mDisableNetworkService;
@@ -909,6 +990,12 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
{
mDisableGPU = message_in.getValueBoolean("disable");
}
+ else if (message_name == "proxy_setup")
+ {
+ mProxyEnabled = message_in.getValueBoolean("enable");
+ mProxyHost = message_in.getValue("host");
+ mProxyPort = message_in.getValueS32("port");
+ }
else if (message_name == "web_security_disabled")
{
mDisableWebSecurity = message_in.getValueBoolean("disabled");
diff --git a/indra/media_plugins/gstreamer10/CMakeLists.txt b/indra/media_plugins/gstreamer10/CMakeLists.txt
new file mode 100644
index 0000000000..730a2c27fb
--- /dev/null
+++ b/indra/media_plugins/gstreamer10/CMakeLists.txt
@@ -0,0 +1,78 @@
+# -*- cmake -*-
+
+project(media_plugin_gstreamer10)
+
+include(00-Common)
+include(LLCommon)
+include(LLImage)
+include(LLPlugin)
+include(LLMath)
+include(LLRender)
+include(LLWindow)
+include(Linking)
+include(PluginAPI)
+include(MediaPluginBase)
+include(OpenGL)
+include(GLIB)
+
+include(GStreamer10Plugin)
+
+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}
+ ${GSTREAMER10_INCLUDE_DIRS}
+ ${GSTREAMER10_PLUGINS_BASE_INCLUDE_DIRS}
+)
+include_directories(SYSTEM
+ ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
+ )
+
+### media_plugin_gstreamer10
+
+if(NOT WORD_SIZE EQUAL 32)
+ if(NOT WINDOWS) # not windows therefore gcc LINUX and DARWIN
+ add_definitions(-fPIC)
+ endif()
+endif(NOT WORD_SIZE EQUAL 32)
+
+set(media_plugin_gstreamer10_SOURCE_FILES
+ media_plugin_gstreamer10.cpp
+ llmediaimplgstreamer_syms.cpp
+ )
+
+set(media_plugin_gstreamer10_HEADER_FILES
+ llmediaimplgstreamer_syms.h
+ llmediaimplgstreamertriviallogging.h
+ )
+
+add_library(media_plugin_gstreamer10
+ SHARED
+ ${media_plugin_gstreamer10_SOURCE_FILES}
+)
+
+target_link_libraries(media_plugin_gstreamer10
+ ${LLPLUGIN_LIBRARIES}
+ ${MEDIA_PLUGIN_BASE_LIBRARIES}
+ ${LLCOMMON_LIBRARIES}
+ ${PLUGIN_API_WINDOWS_LIBRARIES}
+ ${GSTREAMER10_LIBRARIES}
+)
+
+#add_dependencies(media_plugin_gstreamer10
+# ${LLPLUGIN_LIBRARIES}
+# ${MEDIA_PLUGIN_BASE_LIBRARIES}
+# ${LLCOMMON_LIBRARIES}
+#)
+
+if (WINDOWS)
+ set_target_properties(
+ media_plugin_gstreamer10
+ PROPERTIES
+ LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMT"
+ )
+endif (WINDOWS)
diff --git a/indra/newview/llappviewerlinux_api_dbus.h b/indra/media_plugins/gstreamer10/llmediaimplgstreamer.h
similarity index 60%
rename from indra/newview/llappviewerlinux_api_dbus.h
rename to indra/media_plugins/gstreamer10/llmediaimplgstreamer.h
index 3eee25b53d..6bc272c009 100644
--- a/indra/newview/llappviewerlinux_api_dbus.h
+++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer.h
@@ -1,8 +1,10 @@
/**
- * @file llappviewerlinux_api_dbus.h
- * @brief DBus-glib symbol handling
+ * @file llmediaimplgstreamer.h
+ * @author Tofu Linden
+ * @brief implementation that supports media playback via GStreamer.
*
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
+ * @cond
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
@@ -22,23 +24,30 @@
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
+ * @endcond
*/
-#include "linden_common.h"
+// header guard
+#ifndef llmediaimplgstreamer_h
+#define llmediaimplgstreamer_h
-#if LL_DBUS_ENABLED
+#if LL_GSTREAMER010_ENABLED
extern "C" {
-#include
+#include
+#include
+
+#include "apr_pools.h"
+#include "apr_dso.h"
}
-#define DBUSGLIB_DYLIB_DEFAULT_NAME "libdbus-glib-1.so.2"
-bool grab_dbus_syms(std::string dbus_dso_name);
-void ungrab_dbus_syms();
+extern "C" {
+gboolean llmediaimplgstreamer_bus_callback (GstBus *bus,
+ GstMessage *message,
+ gpointer data);
+}
-#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) extern RTN (*ll##DBUSSYM)(__VA_ARGS__)
-#include "llappviewerlinux_api_dbus_syms_raw.inc"
-#undef LL_DBUS_SYM
+#endif // LL_GSTREAMER010_ENABLED
-#endif // LL_DBUS_ENABLED
+#endif // llmediaimplgstreamer_h
diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.cpp
new file mode 100644
index 0000000000..e5e5c1c9a3
--- /dev/null
+++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.cpp
@@ -0,0 +1,197 @@
+/**
+ * @file llmediaimplgstreamer_syms.cpp
+ * @brief dynamic GStreamer symbol-grabbing code
+ *
+ * @cond
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ * @endcond
+ */
+
+#include
+#include
+#include
+
+#ifdef LL_WINDOWS
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0502
+#include
+#endif
+
+#include "linden_common.h"
+
+extern "C" {
+#include
+#include
+}
+
+#include "apr_pools.h"
+#include "apr_dso.h"
+
+#ifdef LL_WINDOWS
+
+#ifndef _M_AMD64
+#define GSTREAMER_REG_KEY "Software\\GStreamer1.0\\x86"
+#define GSTREAMER_DIR_SUFFIX "1.0\\x86\\bin\\"
+#else
+#define GSTREAMER_REG_KEY "Software\\GStreamer1.0\\x86_64"
+#define GSTREAMER_DIR_SUFFIX "1.0\\x86_64\\bin\\"
+#endif
+
+bool openRegKey( HKEY &aKey )
+{
+ // Try native (32 bit view/64 bit view) of registry first.
+ if( ERROR_SUCCESS == ::RegOpenKeyExA( HKEY_LOCAL_MACHINE, GSTREAMER_REG_KEY, 0, KEY_QUERY_VALUE, &aKey ) )
+ return true;
+
+ // If native view fails, use 32 bit view or registry.
+ if( ERROR_SUCCESS == ::RegOpenKeyExA( HKEY_LOCAL_MACHINE, GSTREAMER_REG_KEY, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &aKey ) )
+ return true;
+
+ return false;
+}
+
+std::string getGStreamerDir()
+{
+ std::string ret;
+ HKEY hKey;
+
+ if( openRegKey( hKey ) )
+ {
+ DWORD dwLen(0);
+ ::RegQueryValueExA( hKey, "InstallDir", nullptr, nullptr, nullptr, &dwLen );
+
+ if( dwLen > 0 )
+ {
+ std::vector< char > vctBuffer;
+ vctBuffer.resize( dwLen );
+ ::RegQueryValueExA( hKey, "InstallDir", nullptr, nullptr, reinterpret_cast< LPBYTE>(&vctBuffer[ 0 ]), &dwLen );
+ ret = &vctBuffer[0];
+
+ if( ret[ dwLen-1 ] != '\\' )
+ ret += "\\";
+ ret += GSTREAMER_DIR_SUFFIX;
+
+ SetDllDirectoryA( ret.c_str() );
+ }
+ ::RegCloseKey( hKey );
+ }
+ return ret;
+}
+#else
+std::string getGStreamerDir() { return ""; }
+#endif
+
+#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL;
+#include "llmediaimplgstreamer_syms_raw.inc"
+#undef LL_GST_SYM
+
+struct Symloader
+{
+ bool mRequired;
+ char const *mName;
+ apr_dso_handle_sym_t *mPPFunc;
+};
+
+#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) { REQ, #GSTSYM , (apr_dso_handle_sym_t*)&ll##GSTSYM},
+Symloader sSyms[] = {
+#include "llmediaimplgstreamer_syms_raw.inc"
+{ false, 0, 0 } };
+#undef LL_GST_SYM
+
+// a couple of stubs for disgusting reasons
+GstDebugCategory*
+ll_gst_debug_category_new(gchar *name, guint color, gchar *description)
+{
+ static GstDebugCategory dummy;
+ return &dummy;
+}
+void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname)
+{
+}
+
+static bool sSymsGrabbed = false;
+static apr_pool_t *sSymGSTDSOMemoryPool = NULL;
+
+std::vector< apr_dso_handle_t* > sLoadedLibraries;
+
+bool grab_gst_syms( std::vector< std::string > const &aDSONames )
+{
+ if (sSymsGrabbed)
+ return true;
+
+ //attempt to load the shared libraries
+ apr_pool_create(&sSymGSTDSOMemoryPool, NULL);
+
+ for( std::vector< std::string >::const_iterator itr = aDSONames.begin(); itr != aDSONames.end(); ++itr )
+ {
+ apr_dso_handle_t *pDSO(NULL);
+ std::string strDSO = getGStreamerDir() + *itr;
+ if( APR_SUCCESS == apr_dso_load( &pDSO, strDSO.c_str(), sSymGSTDSOMemoryPool ))
+ sLoadedLibraries.push_back( pDSO );
+
+ for( int i = 0; sSyms[ i ].mName; ++i )
+ {
+ if( !*sSyms[ i ].mPPFunc )
+ {
+ apr_dso_sym( sSyms[ i ].mPPFunc, pDSO, sSyms[ i ].mName );
+ }
+ }
+ }
+
+ std::stringstream strm;
+ bool sym_error = false;
+ for( int i = 0; sSyms[ i ].mName; ++i )
+ {
+ if( sSyms[ i ].mRequired && ! *sSyms[ i ].mPPFunc )
+ {
+ sym_error = true;
+ strm << sSyms[ i ].mName << std::endl;
+ }
+ }
+
+ sSymsGrabbed = !sym_error;
+ return sSymsGrabbed;
+}
+
+
+void ungrab_gst_syms()
+{
+ // should be safe to call regardless of whether we've
+ // actually grabbed syms.
+
+ for( std::vector< apr_dso_handle_t* >::iterator itr = sLoadedLibraries.begin(); itr != sLoadedLibraries.end(); ++itr )
+ apr_dso_unload( *itr );
+
+ sLoadedLibraries.clear();
+
+ if ( sSymGSTDSOMemoryPool )
+ {
+ apr_pool_destroy(sSymGSTDSOMemoryPool);
+ sSymGSTDSOMemoryPool = NULL;
+ }
+
+ for( int i = 0; sSyms[ i ].mName; ++i )
+ *sSyms[ i ].mPPFunc = NULL;
+
+ sSymsGrabbed = false;
+}
+
diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.h b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.h
new file mode 100644
index 0000000000..0874644ee6
--- /dev/null
+++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.h
@@ -0,0 +1,68 @@
+/**
+ * @file llmediaimplgstreamer_syms.h
+ * @brief dynamic GStreamer symbol-grabbing code
+ *
+ * @cond
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ * @endcond
+ */
+
+#include "linden_common.h"
+#include
+extern "C" {
+#include
+}
+
+bool grab_gst_syms( std::vector< std::string > const&);
+void ungrab_gst_syms();
+
+#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__);
+#include "llmediaimplgstreamer_syms_raw.inc"
+#undef LL_GST_SYM
+
+// regrettable hacks to give us better runtime compatibility with older systems
+#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0)
+#define llg_return_val_if_fail(COND,V) do{if (!(COND)) return V;}while(0)
+
+// regrettable hacks because GStreamer was not designed for runtime loading
+#undef GST_TYPE_MESSAGE
+#define GST_TYPE_MESSAGE (llgst_message_get_type())
+#undef GST_TYPE_OBJECT
+#define GST_TYPE_OBJECT (llgst_object_get_type())
+#undef GST_TYPE_PIPELINE
+#define GST_TYPE_PIPELINE (llgst_pipeline_get_type())
+#undef GST_TYPE_ELEMENT
+#define GST_TYPE_ELEMENT (llgst_element_get_type())
+#undef GST_TYPE_VIDEO_SINK
+#define GST_TYPE_VIDEO_SINK (llgst_video_sink_get_type())
+// more regrettable hacks to stub-out these .h-exposed GStreamer internals
+void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname);
+#undef _gst_debug_register_funcptr
+#define _gst_debug_register_funcptr ll_gst_debug_register_funcptr
+GstDebugCategory* ll_gst_debug_category_new(gchar *name, guint color, gchar *description);
+#undef _gst_debug_category_new
+#define _gst_debug_category_new ll_gst_debug_category_new
+#undef __gst_debug_enabled
+#define __gst_debug_enabled (0)
+
+// more hacks
+#define LLGST_MESSAGE_TYPE_NAME(M) (llgst_message_type_get_name(GST_MESSAGE_TYPE(M)))
diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc
new file mode 100644
index 0000000000..da1aa8ec1d
--- /dev/null
+++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc
@@ -0,0 +1,68 @@
+LL_GST_SYM(true, gst_buffer_new, GstBuffer*, void)
+LL_GST_SYM(true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*)
+LL_GST_SYM(true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err)
+LL_GST_SYM(true, gst_message_get_type, GType, void)
+LL_GST_SYM(true, gst_message_type_get_name, const gchar*, GstMessageType type)
+LL_GST_SYM(true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug)
+LL_GST_SYM(true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug)
+LL_GST_SYM(true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending)
+LL_GST_SYM(true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state)
+LL_GST_SYM(true, gst_object_unref, void, gpointer object)
+LL_GST_SYM(true, gst_object_get_type, GType, void)
+LL_GST_SYM(true, gst_pipeline_get_type, GType, void)
+LL_GST_SYM(true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline)
+LL_GST_SYM(true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data)
+LL_GST_SYM(true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name)
+LL_GST_SYM(true, gst_element_get_type, GType, void)
+LL_GST_SYM(true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template)
+LL_GST_SYM(true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp)
+LL_GST_SYM(true, gst_caps_from_string, GstCaps *, const gchar *string)
+LL_GST_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index)
+LL_GST_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type)
+LL_GST_SYM(true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value)
+LL_GST_SYM(true, gst_structure_get_value, G_CONST_RETURN GValue *, const GstStructure *structure, const gchar *fieldname)
+LL_GST_SYM(true, gst_value_get_fraction_numerator, gint, const GValue *value)
+LL_GST_SYM(true, gst_value_get_fraction_denominator, gint, const GValue *value)
+LL_GST_SYM(true, gst_structure_get_name, G_CONST_RETURN gchar *, const GstStructure *structure)
+LL_GST_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64)
+
+LL_GST_SYM(false, gst_registry_fork_set_enabled, void, gboolean enabled)
+LL_GST_SYM(false, gst_segtrap_set_enabled, void, gboolean enabled)
+LL_GST_SYM(false, gst_message_parse_buffering, void, GstMessage *message, gint *percent)
+LL_GST_SYM(false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug)
+LL_GST_SYM(false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur)
+LL_GST_SYM(false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano)
+
+LL_GST_SYM( true, gst_message_parse_tag, void, GstMessage *, GstTagList **)
+LL_GST_SYM( true, gst_tag_list_foreach, void, const GstTagList *, GstTagForeachFunc, gpointer)
+LL_GST_SYM( true, gst_tag_list_get_tag_size, guint, const GstTagList *, const gchar *)
+LL_GST_SYM( true, gst_tag_list_get_value_index, const GValue *, const GstTagList *, const gchar *, guint)
+
+LL_GST_SYM( true, gst_caps_new_simple, GstCaps*, const char *, const char*, ... )
+
+LL_GST_SYM( true, gst_sample_get_caps, GstCaps*, GstSample* )
+LL_GST_SYM( true, gst_sample_get_buffer, GstBuffer*, GstSample* )
+LL_GST_SYM( true, gst_buffer_map, gboolean, GstBuffer*, GstMapInfo*, GstMapFlags )
+LL_GST_SYM( true, gst_buffer_unmap, void, GstBuffer*, GstMapInfo* )
+
+LL_GST_SYM( true, gst_app_sink_set_caps, void, GstAppSink*, GstCaps const* )
+LL_GST_SYM( true, gst_app_sink_pull_sample, GstSample*, GstAppSink* )
+
+LL_GST_SYM( true, g_free, void, gpointer )
+LL_GST_SYM( true, g_error_free, void, GError* )
+
+LL_GST_SYM( true, g_main_context_pending, gboolean, GMainContext* )
+LL_GST_SYM( true, g_main_loop_get_context, GMainContext*, GMainLoop* )
+LL_GST_SYM( true, g_main_context_iteration, gboolean, GMainContext*, gboolean )
+LL_GST_SYM( true, g_main_loop_new, GMainLoop*, GMainContext*, gboolean )
+LL_GST_SYM( true, g_main_loop_quit, void, GMainLoop* )
+LL_GST_SYM( true, gst_mini_object_unref, void, GstMiniObject* )
+LL_GST_SYM( true, g_object_set, void, gpointer, gchar const*, ... )
+LL_GST_SYM( true, g_source_remove, gboolean, guint )
+LL_GST_SYM( true, g_value_get_string, gchar const*, GValue const* )
+
+
+LL_GST_SYM( true, gst_debug_set_active, void, gboolean )
+LL_GST_SYM( true, gst_debug_add_log_function, void, GstLogFunction, gpointer, GDestroyNotify )
+LL_GST_SYM( true, gst_debug_set_default_threshold, void, GstDebugLevel )
+LL_GST_SYM( true, gst_debug_message_get , gchar const*, GstDebugMessage * )
\ No newline at end of file
diff --git a/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp b/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp
new file mode 100644
index 0000000000..5c931ea8f0
--- /dev/null
+++ b/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp
@@ -0,0 +1,980 @@
+/**
+ * @file media_plugin_gstreamer10.cpp
+ * @brief GStreamer-1.0 plugin for LLMedia API plugin system
+ *
+ * @cond
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2016, Linden Research, Inc. / Nicky Dasmijn
+ *
+ * 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
+ */
+
+#define FLIP_Y
+
+#include "linden_common.h"
+
+#include "llgl.h"
+
+#include "llplugininstance.h"
+#include "llpluginmessage.h"
+#include "llpluginmessageclasses.h"
+#include "media_plugin_base.h"
+
+#define G_DISABLE_CAST_CHECKS
+extern "C" {
+#include
+#include
+
+}
+
+#include "llmediaimplgstreamer.h"
+#include "llmediaimplgstreamer_syms.h"
+
+static inline void llgst_caps_unref( GstCaps * caps )
+{
+ llgst_mini_object_unref( GST_MINI_OBJECT_CAST( caps ) );
+}
+
+static inline void llgst_sample_unref( GstSample *aSample )
+{
+ llgst_mini_object_unref( GST_MINI_OBJECT_CAST( aSample ) );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+class MediaPluginGStreamer10 : public MediaPluginBase
+{
+public:
+ MediaPluginGStreamer10(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+ ~MediaPluginGStreamer10();
+
+ /* virtual */ void receiveMessage(const char *message_string);
+
+ static bool startup();
+ static bool closedown();
+
+ 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);
+
+ double MIN_LOOP_SEC = 1.0F;
+ U32 INTERNAL_TEXTURE_SIZE = 1024;
+
+ 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 );
+
+ static bool mDoneInit;
+
+ guint mBusWatchID;
+
+ float mVolume;
+
+ int mDepth;
+
+ // padded texture size we need to write into
+ int mTextureWidth;
+ int mTextureHeight;
+
+ bool mSeekWanted;
+ double mSeekDestination;
+
+ // Very GStreamer-specific
+ GMainLoop *mPump; // event pump for this media
+ GstElement *mPlaybin;
+ GstAppSink *mAppSink;
+};
+
+//static
+bool MediaPluginGStreamer10::mDoneInit = false;
+
+MediaPluginGStreamer10::MediaPluginGStreamer10( LLPluginInstance::sendMessageFunction host_send_func,
+ void *host_user_data )
+ : MediaPluginBase(host_send_func, host_user_data)
+ , mBusWatchID ( 0 )
+ , mSeekWanted(false)
+ , mSeekDestination(0.0)
+ , mPump ( NULL )
+ , mPlaybin ( NULL )
+ , mAppSink ( NULL )
+ , mCommand ( COMMAND_NONE )
+{
+}
+
+gboolean MediaPluginGStreamer10::processGSTEvents(GstBus *bus, GstMessage *message)
+{
+ if (!message)
+ return TRUE; // shield against GStreamer bug
+
+ switch (GST_MESSAGE_TYPE (message))
+ {
+ case GST_MESSAGE_BUFFERING:
+ {
+ // NEEDS GST 0.10.11+
+ if (llgst_message_parse_buffering)
+ {
+ gint percent = 0;
+ llgst_message_parse_buffering(message, &percent);
+ }
+ break;
+ }
+ case GST_MESSAGE_STATE_CHANGED:
+ {
+ GstState old_state;
+ GstState new_state;
+ GstState pending_state;
+ llgst_message_parse_state_changed(message,
+ &old_state,
+ &new_state,
+ &pending_state);
+
+ 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;
+
+ llgst_message_parse_error (message, &err, &debug);
+ if (err)
+ llg_error_free (err);
+ llg_free (debug);
+
+ mCommand = COMMAND_STOP;
+
+ setStatus(STATUS_ERROR);
+
+ break;
+ }
+ case GST_MESSAGE_INFO:
+ {
+ if (llgst_message_parse_info)
+ {
+ GError *err = NULL;
+ gchar *debug = NULL;
+
+ llgst_message_parse_info (message, &err, &debug);
+ if (err)
+ llg_error_free (err);
+ llg_free (debug);
+ }
+ break;
+ }
+ case GST_MESSAGE_WARNING:
+ {
+ GError *err = NULL;
+ gchar *debug = NULL;
+
+ llgst_message_parse_warning (message, &err, &debug);
+ if (err)
+ llg_error_free (err);
+ llg_free (debug);
+
+ break;
+ }
+ case GST_MESSAGE_EOS:
+ /* end-of-stream */
+ if (mIsLooping)
+ {
+ 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
+ // inject a COMMAND_PAUSE
+ mCommand = COMMAND_PAUSE;
+ }
+ else
+ {
+ 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)
+ {
+ MediaPluginGStreamer10 *impl = (MediaPluginGStreamer10*)data;
+ return impl->processGSTEvents(bus, message);
+ }
+} // extern "C"
+
+
+
+bool MediaPluginGStreamer10::navigateTo ( const std::string urlIn )
+{
+ if (!mDoneInit)
+ return false; // error
+
+ setStatus(STATUS_LOADING);
+
+ mSeekWanted = false;
+
+ if (NULL == mPump || NULL == mPlaybin)
+ {
+ setStatus(STATUS_ERROR);
+ return false; // error
+ }
+
+ llg_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL);
+
+ // navigateTo implicitly plays, too.
+ play(1.0);
+
+ return true;
+}
+
+
+class GstSampleUnref
+{
+ GstSample *mT;
+public:
+ GstSampleUnref( GstSample *aT )
+ : mT( aT )
+ { llassert_always( mT ); }
+
+ ~GstSampleUnref( )
+ { llgst_sample_unref( mT ); }
+};
+
+bool MediaPluginGStreamer10::update(int milliseconds)
+{
+ if (!mDoneInit)
+ return false; // error
+
+ // DEBUGMSG("updating media...");
+
+ // sanity check
+ if (NULL == mPump || NULL == mPlaybin)
+ {
+ 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 (llg_main_context_pending(llg_main_loop_get_context(mPump)))
+ {
+ llg_main_context_iteration(llg_main_loop_get_context(mPump), FALSE);
+ }
+
+ // check for availability of a new frame
+
+ if( !mAppSink )
+ return true;
+
+ if( GST_STATE(mPlaybin) != GST_STATE_PLAYING) // Do not try to pull a sample if not in playing state
+ return true;
+
+ GstSample *pSample = llgst_app_sink_pull_sample( mAppSink );
+ if(!pSample)
+ return false; // Done playing
+
+ GstSampleUnref oSampleUnref( pSample );
+ GstCaps *pCaps = llgst_sample_get_caps ( pSample );
+ if (!pCaps)
+ return false;
+
+ gint width, height;
+ GstStructure *pStruct = llgst_caps_get_structure ( pCaps, 0);
+
+ int res = llgst_structure_get_int ( pStruct, "width", &width);
+ res |= llgst_structure_get_int ( pStruct, "height", &height);
+
+ if( !mPixels )
+ return true;
+
+ GstBuffer *pBuffer = llgst_sample_get_buffer ( pSample );
+ GstMapInfo map;
+ llgst_buffer_map ( pBuffer, &map, GST_MAP_READ);
+
+ // Our render buffer is always 1kx1k
+
+ U32 rowSkip = INTERNAL_TEXTURE_SIZE / mTextureHeight;
+ U32 colSkip = INTERNAL_TEXTURE_SIZE / mTextureWidth;
+
+ for (int row = 0; row < mTextureHeight; ++row)
+ {
+ U8 const *pTexelIn = map.data + (row*rowSkip * width *3);
+#ifndef FLIP_Y
+ U8 *pTexelOut = mPixels + (row * mTextureWidth * mDepth );
+#else
+ U8 *pTexelOut = mPixels + ((mTextureHeight-row-1) * mTextureWidth * mDepth );
+#endif
+ for( int col = 0; col < mTextureWidth; ++col )
+ {
+ pTexelOut[ 0 ] = pTexelIn[0];
+ pTexelOut[ 1 ] = pTexelIn[1];
+ pTexelOut[ 2 ] = pTexelIn[2];
+ pTexelOut += mDepth;
+ pTexelIn += colSkip*3;
+ }
+ }
+
+ llgst_buffer_unmap( pBuffer, &map );
+ setDirty(0,0,mTextureWidth,mTextureHeight);
+
+ return true;
+}
+
+void MediaPluginGStreamer10::mouseDown( int x, int y )
+{
+ // do nothing
+}
+
+void MediaPluginGStreamer10::mouseUp( int x, int y )
+{
+ // do nothing
+}
+
+void MediaPluginGStreamer10::mouseMove( int x, int y )
+{
+ // do nothing
+}
+
+
+bool MediaPluginGStreamer10::pause()
+{
+ // todo: error-check this?
+ if (mDoneInit && mPlaybin)
+ {
+ llgst_element_set_state(mPlaybin, GST_STATE_PAUSED);
+ return true;
+ }
+ return false;
+}
+
+bool MediaPluginGStreamer10::stop()
+{
+ // todo: error-check this?
+ if (mDoneInit && mPlaybin)
+ {
+ llgst_element_set_state(mPlaybin, GST_STATE_READY);
+ return true;
+ }
+ return false;
+}
+
+bool MediaPluginGStreamer10::play(double rate)
+{
+ // NOTE: we don't actually support non-natural rate.
+
+ // todo: error-check this?
+ if (mDoneInit && mPlaybin)
+ {
+ llgst_element_set_state(mPlaybin, GST_STATE_PLAYING);
+ return true;
+ }
+ return false;
+}
+
+bool MediaPluginGStreamer10::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)
+ {
+ llg_object_set(mPlaybin, "volume", mVolume, NULL);
+ return true;
+ }
+
+ return false;
+}
+
+bool MediaPluginGStreamer10::seek(double time_sec)
+{
+ bool success = false;
+ if (mDoneInit && mPlaybin)
+ {
+ success = llgst_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);
+ }
+ return success;
+}
+
+bool MediaPluginGStreamer10::getTimePos(double &sec_out)
+{
+ bool got_position = false;
+ if (mDoneInit && mPlaybin)
+ {
+ gint64 pos(0);
+ GstFormat timefmt = GST_FORMAT_TIME;
+ got_position =
+ llgst_element_query_position &&
+ llgst_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 MediaPluginGStreamer10::load()
+{
+ if (!mDoneInit)
+ return false; // error
+
+ setStatus(STATUS_LOADING);
+
+ mIsLooping = false;
+ mVolume = 0.1234567f; // minor hack to force an initial volume update
+
+ // Create a pumpable main-loop for this media
+ mPump = llg_main_loop_new (NULL, FALSE);
+ if (!mPump)
+ {
+ setStatus(STATUS_ERROR);
+ return false; // error
+ }
+
+ // instantiate a playbin element to do the hard work
+ mPlaybin = llgst_element_factory_make ("playbin", "");
+ if (!mPlaybin)
+ {
+ setStatus(STATUS_ERROR);
+ return false; // error
+ }
+
+ // get playbin's bus
+ GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin));
+ if (!bus)
+ {
+ setStatus(STATUS_ERROR);
+ return false; // error
+ }
+ mBusWatchID = llgst_bus_add_watch (bus,
+ llmediaimplgstreamer_bus_callback,
+ this);
+ llgst_object_unref (bus);
+
+ mAppSink = (GstAppSink*)(llgst_element_factory_make ("appsink", ""));
+
+ GstCaps* pCaps = llgst_caps_new_simple( "video/x-raw",
+ "format", G_TYPE_STRING, "RGB",
+ "width", G_TYPE_INT, INTERNAL_TEXTURE_SIZE,
+ "height", G_TYPE_INT, INTERNAL_TEXTURE_SIZE,
+ NULL );
+
+ llgst_app_sink_set_caps( mAppSink, pCaps );
+ llgst_caps_unref( pCaps );
+
+ if (!mAppSink)
+ {
+ setStatus(STATUS_ERROR);
+ return false;
+ }
+
+ llg_object_set(mPlaybin, "video-sink", mAppSink, NULL);
+
+ return true;
+}
+
+bool MediaPluginGStreamer10::unload ()
+{
+ if (!mDoneInit)
+ return false; // error
+
+ // stop getting callbacks for this bus
+ llg_source_remove(mBusWatchID);
+ mBusWatchID = 0;
+
+ if (mPlaybin)
+ {
+ llgst_element_set_state (mPlaybin, GST_STATE_NULL);
+ llgst_object_unref (GST_OBJECT (mPlaybin));
+ mPlaybin = NULL;
+ }
+
+ if (mPump)
+ {
+ llg_main_loop_quit(mPump);
+ mPump = NULL;
+ }
+
+ mAppSink = NULL;
+
+ setStatus(STATUS_NONE);
+
+ return true;
+}
+
+void LogFunction(GstDebugCategory *category, GstDebugLevel level, const gchar *file, const gchar *function, gint line, GObject *object, GstDebugMessage *message, gpointer user_data )
+#ifndef LL_LINUX // Docu says we need G_GNUC_NO_INSTRUMENT, but GCC says 'error'
+ G_GNUC_NO_INSTRUMENT
+#endif
+{
+#ifdef LL_LINUX
+ std::cerr << file << ":" << line << "(" << function << "): " << llgst_debug_message_get( message ) << std::endl;
+#endif
+}
+
+//static
+bool MediaPluginGStreamer10::startup()
+{
+ // first - check if GStreamer is explicitly disabled
+ if (NULL != getenv("LL_DISABLE_GSTREAMER"))
+ return false;
+
+ // only do global GStreamer initialization once.
+ if (!mDoneInit)
+ {
+ ll_init_apr();
+
+ // Get symbols!
+ std::vector< std::string > vctDSONames;
+#if LL_DARWIN
+#elif LL_WINDOWS
+ vctDSONames.push_back( "libgstreamer-1.0-0.dll" );
+ vctDSONames.push_back( "libgstapp-1.0-0.dll" );
+ vctDSONames.push_back( "libglib-2.0-0.dll" );
+ vctDSONames.push_back( "libgobject-2.0-0.dll" );
+#else // linux or other ELFy unixoid
+ vctDSONames.push_back( "libgstreamer-1.0.so.0" );
+ vctDSONames.push_back( "libgstapp-1.0.so.0" );
+ vctDSONames.push_back( "libglib-2.0.so.0" );
+ vctDSONames.push_back( "libgobject-2.0.so" );
+#endif
+ if( !grab_gst_syms( vctDSONames ) )
+ {
+ return false;
+ }
+
+ if (llgst_segtrap_set_enabled)
+ {
+ llgst_segtrap_set_enabled(FALSE);
+ }
+#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 (llgst_registry_fork_set_enabled ) {
+ // if we can disable SIGCHLD-using forking behaviour,
+ // do it.
+ llgst_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);
+
+// _putenv_s( "GST_PLUGIN_PATH", "E:\\gstreamer\\1.0\\x86\\lib\\gstreamer-1.0" );
+
+ llgst_debug_set_default_threshold( GST_LEVEL_WARNING );
+ llgst_debug_add_log_function( LogFunction, NULL, NULL );
+ llgst_debug_set_active( false );
+
+ // finally, try to initialize GStreamer!
+ GError *err = NULL;
+ gboolean init_gst_success = llgst_init_check(NULL, NULL, &err);
+
+ // restore old locale
+ setlocale(LC_ALL, saved_locale.c_str() );
+
+#if LL_LINUX
+ // restore old SIGCHLD handler
+ if (!llgst_registry_fork_set_enabled)
+ sigaction(SIGCHLD, &oldact, NULL);
+#endif // LL_LINUX
+
+ if (!init_gst_success) // fail
+ {
+ if (err)
+ {
+ llg_error_free(err);
+ }
+ return false;
+ }
+
+ mDoneInit = true;
+ }
+
+ return true;
+}
+
+//static
+bool MediaPluginGStreamer10::closedown()
+{
+ if (!mDoneInit)
+ return false; // error
+
+ ungrab_gst_syms();
+
+ mDoneInit = false;
+
+ return true;
+}
+
+MediaPluginGStreamer10::~MediaPluginGStreamer10()
+{
+ closedown();
+}
+
+
+std::string MediaPluginGStreamer10::getVersion()
+{
+ std::string plugin_version = "GStreamer10 media plugin, GStreamer version ";
+ if (mDoneInit &&
+ llgst_version)
+ {
+ guint major, minor, micro, nano;
+ llgst_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 MediaPluginGStreamer10::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_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
+ message.setValueLLSD("versions", versions);
+
+ load();
+
+ 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");
+
+ 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);
+ }
+
+ // Send the response so it can be cleaned up.
+ LLPluginMessage message("base", "shm_remove_response");
+ message.setValue("name", name);
+ sendMessage(message);
+ }
+ }
+ 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;
+
+ 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", INTERNAL_TEXTURE_SIZE );
+ message.setValueS32("default_height", INTERNAL_TEXTURE_SIZE );
+ 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");
+
+ 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())
+ {
+ mPixels = (unsigned char*)iter->second.mAddress;
+ mTextureSegmentName = name;
+
+ mTextureWidth = texture_width;
+ mTextureHeight = texture_height;
+ memset( mPixels, 0, mTextureWidth*mTextureHeight*mDepth );
+ }
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request");
+ message.setValue("name", mTextureSegmentName);
+ message.setValueS32("width", INTERNAL_TEXTURE_SIZE );
+ message.setValueS32("height", INTERNAL_TEXTURE_SIZE );
+ sendMessage(message);
+
+ }
+ }
+ 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);
+ }
+ }
+ }
+}
+
+int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
+{
+ if( MediaPluginGStreamer10::startup() )
+ {
+ MediaPluginGStreamer10 *self = new MediaPluginGStreamer10(host_send_func, host_user_data);
+ *plugin_send_func = MediaPluginGStreamer10::staticReceiveMessage;
+ *plugin_user_data = (void*)self;
+
+ return 0; // okay
+ }
+ else
+ {
+ return -1; // failed to init
+ }
+}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 3220b89774..6a32d90a65 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -13,7 +13,7 @@ include(BuildPackagesInfo)
include(BuildVersion)
include(CMakeCopyIfDifferent)
include(CubemapToEquirectangularJS)
-include(DBusGlib)
+include(GLIB)
include(DragDrop)
include(EXPAT)
include(FMODSTUDIO)
@@ -1797,7 +1797,6 @@ if (LINUX)
# fsversionstrings.h with the right numbers in it.
# COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}"
)
- LIST(APPEND viewer_SOURCE_FILES llappviewerlinux_api_dbus.cpp)
# [FS] Growl support
LIST(APPEND viewer_HEADER_FILES desktopnotifierlinux.h growlmanager.h)
LIST(APPEND viewer_SOURCE_FILES desktopnotifierlinux.cpp growlmanager.cpp)
@@ -1865,6 +1864,8 @@ if (WINDOWS)
COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}"
)
+ set_source_files_properties( llappviewer.cpp llviewermenu.cpp PROPERTIES COMPILE_FLAGS /bigobj )
+
list(APPEND viewer_HEADER_FILES
llappviewerwin32.h
llwindebug.h
@@ -2518,7 +2519,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${BOOST_WAVE_LIBRARY} #FS specific
${BOOST_THREAD_LIBRARY} #FS specific
${BOOST_CONTEXT_LIBRARY}
- ${DBUSGLIB_LIBRARIES}
+ ${GLIB_LIBRARIES}
${OPENGL_LIBRARIES}
${FMODWRAPPER_LIBRARY} # must come after LLAudio
${OPENAL_LIBRARIES}
@@ -2538,6 +2539,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${LLPHYSICSEXTENSIONS_LIBRARIES}
${LLAPPEARANCE_LIBRARIES}
${GROWL_LIBRARY}
+ ${GIO_LIBRARIES}
)
target_link_libraries(${VIEWER_BINARY_NAME} ${DISCORD_LIBRARY} )
@@ -2565,26 +2567,30 @@ if (LINUX)
set(product Firestorm-${ARCH}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION})
# These are the generated targets that are copied to package/
-if (NOT ENABLE_MEDIA_PLUGINS)
- set(COPY_INPUT_DEPENDENCIES
- ${VIEWER_BINARY_NAME}
- SLPlugin
- media_plugin_cef
- #media_plugin_gstreamer010
- media_plugin_libvlc
- llcommon
- )
-else (NOT ENABLE_MEDIA_PLUGINS)
- set(COPY_INPUT_DEPENDENCIES
- ${VIEWER_BINARY_NAME}
- #linux-crash-logger
- SLPlugin
- media_plugin_cef
- #media_plugin_gstreamer010
- llcommon
- )
-endif (NOT ENABLE_MEDIA_PLUGINS)
+ if (NOT ENABLE_MEDIA_PLUGINS)
+ set(COPY_INPUT_DEPENDENCIES
+ ${VIEWER_BINARY_NAME}
+ SLPlugin
+ media_plugin_cef
+ media_plugin_gstreamer10
+ #media_plugin_libvlc
+ llcommon
+ linux-crash-logger
+ )
+ else (NOT ENABLE_MEDIA_PLUGINS)
+ set(COPY_INPUT_DEPENDENCIES
+ ${VIEWER_BINARY_NAME}
+ #linux-crash-logger
+ SLPlugin
+ media_plugin_cef
+ media_plugin_gstreamer10
+ llcommon
+ linux-crash-logger
+ )
+ endif (NOT ENABLE_MEDIA_PLUGINS)
+ add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer10 media_plugin_cef linux-crash-logger)
+
add_custom_command(
OUTPUT ${product}.tar.bz2
COMMAND ${PYTHON_EXECUTABLE}
@@ -2610,7 +2616,6 @@ endif (NOT ENABLE_MEDIA_PLUGINS)
${COPY_INPUT_DEPENDENCIES}
)
-
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched
COMMAND ${PYTHON_EXECUTABLE}
@@ -2861,8 +2866,10 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
endif (LINUX)
endif (USE_BUGSPLAT)
- # for both Bugsplat and Breakpad
- add_dependencies(llpackage generate_symbols)
+ if (NOT LINUX) #Linux generates symbols via viewer_manifest.py/fs_viewer_manifest.py
+ # for both Bugsplat and Breakpad
+ add_dependencies(llpackage generate_symbols)
+ endif()
endif ()
if (LL_TESTS)
diff --git a/indra/newview/SecondLife.xib b/indra/newview/SecondLife.xib
index ef25c648a7..fbff8fe307 100644
--- a/indra/newview/SecondLife.xib
+++ b/indra/newview/SecondLife.xib
@@ -340,7 +340,7 @@
{10000000000000, 10000000000000}
Second Life
128
- YES
+ NO