Ansariel 2022-03-01 10:00:36 +01:00
commit 25f974d77d
371 changed files with 8365 additions and 10663 deletions

2
.gitignore vendored
View File

@ -111,3 +111,5 @@ compile_commands.json
# ignore tracy for now
indra/tracy
firestorm.code-workspace
.cache/clangd/index/

View File

@ -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

View File

@ -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

View File

@ -3,6 +3,118 @@
<map>
<key>installables</key>
<map>
<key>gstreamer10</key>
<map>
<key>copyright</key>
<string>Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</string>
<key>license</key>
<string>LGPL</string>
<key>license_file</key>
<string>LICENSES/gstreamer.txt</string>
<key>name</key>
<string>gstreamer10</string>
<key>platforms</key>
<map>
<key>linux</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>01f39ecf80dae64e30402ac384035b3e</string>
<key>url</key>
<string>http://downloads.phoenixviewer.com/gstreamer10-1.6.3.201605191852-linux-201605191852.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
</map>
</map>
<key>version</key>
<string>0.10.6.294903</string>
</map>
<key>breakpad</key>
<map>
<key>copyright</key>
<string>Copyright (C) google</string>
<key>license</key>
<string>BSD</string>
<key>license_file</key>
<string>LICENSES/google_breakpad.txt</string>
<key>name</key>
<string>breakpad</string>
<key>platforms</key>
<map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>482c2b25bbfd25edc058a02f82da39b2</string>
<key>url</key>
<string>http://3p.firestormviewer.org/breakpad-4708e6fb-linux64_bionic-220392253.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
</map>
</map>
<key>version</key>
<string>2.48.0</string>
</map>
<key>glib</key>
<map>
<key>copyright</key>
<string>Copyright (C) glib project</string>
<key>license</key>
<string>LGPL</string>
<key>license_file</key>
<string>LICENSES/glib.txt</string>
<key>name</key>
<string>glib</string>
<key>platforms</key>
<map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>9c93ba8b8af97fc8379f77de77e1540a</string>
<key>url</key>
<string>http://3p.firestormviewer.org/glib-2.48.0.202301938-linux64-202301938.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
</map>
</map>
<key>version</key>
<string>2.48.0</string>
</map>
<key>fltk</key>
<map>
<key>copyright</key>
<string>Copyright (C) fltk project</string>
<key>license</key>
<string>LGPL/fltk</string>
<key>license_file</key>
<string>LICENSES/fltk.txt</string>
<key>name</key>
<string>fltk</string>
<key>platforms</key>
<map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>81fe1e927e4fe3c5e5f15ce6219ca883</string>
<key>url</key>
<string>http://3p.firestormviewer.org/fltk-1.3.5.202282121-linux64-202282121.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
</map>
</map>
<key>version</key>
<string>1.3.5</string>
</map>
<key>jemalloc</key>
<map>
<key>copyright</key>
@ -424,9 +536,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>29eb0d338020242454b77b278c11d3e7</string>
<string>401f317fbb67623c97a7b9d8b6627ef1</string>
<key>url</key>
<string>http://3p.firestormviewer.org/boost-1.72-linux64-202021511.tar.bz2</string>
<string>http://3p.firestormviewer.org/boost-1.72-linux64_bionic-220402045.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -549,26 +661,14 @@
<key>name</key>
<string>darwin64</string>
</map>
<key>linux</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>d83896f28716f34b7b49d61a23283c4c</string>
<key>url</key>
<string>http://3p.firestormviewer.org/colladadom-2.3.180871403-linux-180871403.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>df6fe4c80b96ec20b5ee6f56419e6b9f</string>
<string>88ee58d6548deae6c306f125b6461d61</string>
<key>url</key>
<string>http://3p.firestormviewer.org/colladadom-2.3.202021526-linux64-202021526.tar.bz2</string>
<string>http://3p.firestormviewer.org/colladadom-2.3.220402056-linux64_bionic-220402056.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -720,9 +820,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>96dd770f246917589b776300a2d07f9e</string>
<string>0bcccd248a5e4084af4026eee439816b</string>
<key>url</key>
<string>http://3p.firestormviewer.org/curl-7.54.1.212891029-linux64-212891029.tar.bz2</string>
<string>http://3p.firestormviewer.org/curl-7.81.0.220511906-linux64_bionic-220511906.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -787,48 +887,6 @@
<key>version</key>
<string>5.1.25</string>
</map>
<key>dbus_glib</key>
<map>
<key>copyright</key>
<string>Copyright (C) Red Hat Inc.</string>
<key>description</key>
<string>D-Bus bindings for glib</string>
<key>license</key>
<string>Academic Free License v. 2.1</string>
<key>license_file</key>
<string>LICENSES/dbus-glib.txt</string>
<key>name</key>
<string>dbus_glib</string>
<key>platforms</key>
<map>
<key>linux</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>9591dcb7efce2a770d77e907705e1492</string>
<key>url</key>
<string>http://3p.firestormviewer.org/dbus_glib-0.76-linux-180871236.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>5a685a65a7066937ef580dcd5a90f9dc</string>
<key>url</key>
<string>http://3p.firestormviewer.org/dbus_glib-0.76-linux64-180841549.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
</map>
<key>version</key>
<string>0.76</string>
</map>
<key>dictionaries</key>
<map>
<key>copyright</key>
@ -914,9 +972,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>2f8fdc6950620cee3a526ede27e068aa</string>
<string>8d532edd648448d78e6daa0cc5f821f9</string>
<key>url</key>
<string>http://3p.firestormviewer.org/dullahan-1.12.2.202109282040_91.1.23_g04c8d56_chromium-91.0.4472.164-linux64-212711840.tar.bz2</string>
<string>http://3p.firestormviewer.org/dullahan-1.12.2.202202071031_91.1.23_g04c8d56_chromium-91.0.4472.164-linux64-220380931.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -1058,11 +1116,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>bde9eb3e53001584edb1af44e3b265a2</string>
<string>2db00aa4126d4ee8152fc49b03bb3fe1</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>file:///opt/firestorm/fmodstudio-2.02.04-darwin-213491614.tar.bz2</string>
<string>file:///opt/firestorm/fmodstudio-2.02.05-darwin-220160006.tar.bz2</string>
</map>
<key>name</key>
<string>darwin</string>
@ -1577,46 +1635,6 @@
<key>version</key>
<string>0.10.6.314267</string>
</map>
<key>gtk-atk-pango-glib</key>
<map>
<key>copyright</key>
<string>Copyright (various, see sources)</string>
<key>license</key>
<string>lgpl</string>
<key>license_file</key>
<string>LICENSES/gtk-atk-pango-glib.txt</string>
<key>name</key>
<string>gtk-atk-pango-glib</string>
<key>platforms</key>
<map>
<key>linux</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>fb047d496c32cc3b9f99793ee6ebb1e3</string>
<key>url</key>
<string>http://3p.firestormviewer.org/gtk_atk_pango_glib-2.1-linux-180871647.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>d918d894430c1d1d869b9f2e06570c65</string>
<key>url</key>
<string>http://3p.firestormviewer.org/gtk_atk_pango_glib-2.1-linux64-180841902.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
</map>
<key>version</key>
<string>2.1</string>
</map>
<key>havok-source</key>
<map>
<key>copyright</key>
@ -2443,18 +2461,18 @@
<key>archive</key>
<map>
<key>hash</key>
<string>35f42f538f4dc3abdfc2b2c4a915d004</string>
<string>95cb09a712b7b61e992fe68ab7bf8c72</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87228/802959/llca-202109010216.563493-common-563493.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/92744/837149/llca-202201010217.567162-common-567162.tar.bz2</string>
</map>
<key>name</key>
<string>common</string>
</map>
</map>
<key>version</key>
<string>202109010216.563493</string>
<string>202201010217.567162</string>
</map>
<key>llphysicsextensions_source</key>
<map>
@ -2473,9 +2491,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>14fac452271ebfba37ba5ddcf5bffa54</string>
<string>da57838d80cf332f4a3026713a13f086</string>
<key>url</key>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54842/510078/llphysicsextensions_source-1.0.538972-darwin64-538972.tar.bz2</string>
<string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/90708/824484/llphysicsextensions_source-1.0.565754-darwin64-565754.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -2497,16 +2515,16 @@
<key>archive</key>
<map>
<key>hash</key>
<string>f3c066c1aebed8a6519a3e5ce64b9a3c</string>
<string>28ad884012aa0bb70cf4101853af2f9a</string>
<key>url</key>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54982/511796/llphysicsextensions_source-1.0.538972-windows-538972.tar.bz2</string>
<string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/90733/824570/llphysicsextensions_source-1.0.565768-windows-565768.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
</map>
</map>
<key>version</key>
<string>1.0.538972</string>
<string>1.0.565768</string>
</map>
<key>llphysicsextensions_stub</key>
<map>
@ -3424,9 +3442,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>c42575ac8997de979eadb082c33a578e</string>
<string>b97d0f6570104277de92d0d3f2d1111d</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81322/765512/uriparser-0.9.4-darwin64-559132.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89474/816487/uriparser-0.9.4-darwin64-564957.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -3460,9 +3478,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>901b1063556fc6b2575e745eef2bf744</string>
<string>e2600c798e220cc98c1cc77341aee00d</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81323/765528/uriparser-0.9.4-windows-559132.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89476/816496/uriparser-0.9.4-windows-564957.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@ -3472,9 +3490,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>962c01d553f286c430102998129fb0d6</string>
<string>50d857117d31844fc8b84b07b795fd00</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81324/765527/uriparser-0.9.4-windows64-559132.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89475/816497/uriparser-0.9.4-windows64-564957.tar.bz2</string>
</map>
<key>name</key>
<string>windows64</string>
@ -3502,9 +3520,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>a3c8357a2f5a62cd7de43181b02553bc</string>
<string>33ed1bb3e24fbd3462da04fb3e917e94</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/91396/829032/viewer_manager-2.0.566227-darwin64-566227.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/94814/850320/viewer_manager-3.0.568552-darwin64-568552.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -3538,9 +3556,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>0654b449d9bdf3507664cf5caa67336f</string>
<string>2ad8e04965ac8bddb7d351abe09bee07</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/91397/829041/viewer_manager-2.0.566227-windows-566227.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/94813/850316/viewer_manager-3.0.568552-windows-568552.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@ -3551,7 +3569,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>source_type</key>
<string>hg</string>
<key>version</key>
<string>2.0.566227</string>
<string>3.0.568552</string>
</map>
<key>vlc-bin</key>
<map>
@ -3577,30 +3595,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>name</key>
<string>darwin64</string>
</map>
<key>linux</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>9f9582031af3b78d6153ec296d6dde9f</string>
<key>url</key>
<string>http://3p.firestormviewer.org/vlc_bin-2.2.3-linux-201607071822-r16.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>5eace400c487011a678493fc520be24d</string>
<key>url</key>
<string>http://3p.firestormviewer.org/vlc_bin-2.2.3-linux-x64-201610182130-r16.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
<key>windows</key>
<map>
<key>archive</key>

View File

@ -280,6 +280,7 @@ Beq Janus
SL-14766
SL-14927
SL-11300
SL-16021
Beth Walcher
Bezilon Kasei
Biancaluce Robbiani
@ -1111,6 +1112,7 @@ Nicky Dasmijn
OPEN-187
STORM-1937
OPEN-187
SL-15234
STORM-2010
STORM-2082
MAINT-6665
@ -1120,6 +1122,7 @@ Nicky Dasmijn
SL-11072
SL-13141
SL-13642
SL-16438
Nicky Perian
OPEN-1
STORM-1087

View File

@ -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)

View File

@ -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()
# <FS:ND/>
# 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)

View File

@ -20,7 +20,7 @@ set(cmake_SOURCE_FILES
ConfigurePkgConfig.cmake
CURL.cmake
Copy3rdPartyLibs.cmake
DBusGlib.cmake
GLIB.cmake
DeploySharedLibs.cmake
Discord.cmake # <FS:LO> Discord rich presence
DragDrop.cmake

View File

@ -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

View File

@ -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)

View File

@ -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) #<FS:ND/> Also add freetype2 to search dir, or some includes will fail.
set(FREETYPE_LIBRARIES freetype)
# <FS:ND> Linux links this via UI.cmake
if( NOT LINUX )
set(FREETYPE_LIBRARIES freetype)
endif()
# </FS:ND>
endif (USESYSTEMLIBS)
link_directories(${FREETYPE_LIBRARY_DIRS})

11
indra/cmake/GLIB.cmake Normal file
View File

@ -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()

View File

@ -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)

View File

@ -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()

View File

@ -1,5 +1,26 @@
# -*- cmake -*-
# <FS:ND> 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/

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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)
# <FS:ND/> 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)

View File

@ -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

View File

@ -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 <grid>
--farm <grid>
--region <starting region name>
"""
""")
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-<xxx>/newview/<target>
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)

View File

@ -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.")

View File

@ -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 = []

View File

@ -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]

View File

@ -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

View File

@ -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'])
# <FS:ND> 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.

View File

@ -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 <srcFileName> <assemblyName> <assemblyVersion>'
@ -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)

View File

@ -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

View File

@ -24,35 +24,77 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llcrashloggerlinux.h"
#include "llsdutil.h"
#include <iostream>
#include <string>
#include <curl/curl.h>
#include <FL/fl_ask.H>
/* 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;
}

View File

@ -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 <iostream>
#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
// <FS:ND> 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";
// </FS:ND>
#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()
{
// <FS:ND> 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());
// </FS:ND>
if(send_logs)
{
sendCrashLogs();
}
return true;
}
bool LLCrashLoggerLinux::cleanup()
{
commonCleanup();
mKeyMaster.releaseMaster();
return true;
}
void LLCrashLoggerLinux::updateApplication(const std::string& message)
{
LLCrashLogger::updateApplication(message);
}

View File

@ -11,7 +11,7 @@ include(LLMath)
include(LLMessage)
include(LLFileSystem)
include_directories(
include_directories( SYSTEM
${LLAUDIO_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}

View File

@ -13,7 +13,7 @@ include(Copy3rdPartyLibs)
include(ZLIB)
include(URIPARSER)
include_directories(
include_directories( SYSTEM
${EXPAT_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${JSONCPP_INCLUDE_DIR}

View File

@ -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);
}
}
}
}

View File

@ -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; /*<FS:ND> 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)

View File

@ -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]);
}

View File

@ -189,7 +189,6 @@ LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic()
void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd)
{
incrementCurrentCount() ;
(*sd)[getCurrentLabelName()]["Name"] = mName ;
}
void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd)

View File

@ -48,6 +48,12 @@
#include <set>
#include <boost/range.hpp>
// <FS:ND> Suppress warnings about the string fiddling
#if LL_LINUX
#pragma GCC diagnostic ignored "-Wstringop-truncation"
#endif
// </FS:ND>
// U32
LLSD ll_sd_from_U32(const U32 val)
{

View File

@ -1273,18 +1273,12 @@ BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile)
LLFILE *dst = NULL;
S32 bytes = 0;
tmpfile = dstfile + ".t";
// <FS:ND> 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
// </FS:ND>
if (! src) goto err;
dst = LLFile::fopen(tmpfile, "wb"); /* Flawfinder: ignore */
if (! dst) goto err;
@ -1319,17 +1313,13 @@ BOOL gzip_file(const std::string& srcfile, const std::string& dstfile)
S32 bytes = 0;
tmpfile = dstfile + ".t";
// <FS:ND> 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
// </FS:ND>
if (! dst) goto err;
src = LLFile::fopen(srcfile, "rb"); /* Flawfinder: ignore */
if (! src) goto err;

View File

@ -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"

View File

@ -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<const char*> 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();

View File

@ -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;

View File

@ -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());
// <FS:ND/> 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);

View File

@ -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);
// <FS:ND/> 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);

View File

@ -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

View File

@ -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

View File

@ -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) // <FS:Beq/> avoid pointless warning when LL_PATH_NONE is used.
{
LL_WARNS() << ELLPathToString(location)
<< ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename

View File

@ -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<LLFolderDictionary>,
@ -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)); // <FS:Ansariel> 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)); // <FS:Ansariel> 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)); // <FS:Ansariel> OpenSim HG-support
addEntry(LLFolderType::FT_MY_SUITCASE, new FolderEntry("suitcase", TRUE, FALSE, TRUE)); // <FS:Ansariel> 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)

View File

@ -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);

View File

@ -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
@ -6444,8 +6466,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();
@ -6546,7 +6578,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)

View File

@ -35,6 +35,12 @@
#include "llstring.h"
#include "llstringtable.h"
// <FS:ND> Suppress warnings about the string fiddling
#if LL_LINUX
#pragma GCC diagnostic ignored "-Wstringop-truncation"
#endif
// </FS:ND>
// 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

View File

@ -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

View File

@ -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()

View File

@ -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:

View File

@ -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;

View File

@ -242,6 +242,17 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& 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)
{

View File

@ -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()
{

View File

@ -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 <class T>

View File

@ -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

View File

@ -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);
}

View File

@ -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; <FS:ND/> 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);

View File

@ -500,8 +500,7 @@ LLNotification::LLNotification(const LLSDParamAdapter<Params>& p) :
mResponderObj(NULL),
mId(p.id.isProvided() ? p.id : LLUUID::generateNewID()),
mOfferFromAgent(p.offer_from_agent),
mIsDND(p.is_dnd),
mIsFromStorage(false)// <FS:Ansariel> 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;

View File

@ -399,7 +399,6 @@ private:
LLNotificationResponderPtr mResponder;
bool mOfferFromAgent;
bool mIsDND;
bool mIsFromStorage; // <FS:Ansariel> 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;
}
// <FS:Ansariel> FIRE-11339: Persisted group notifications get logged to IM on each login
bool isFromStorage() const
{
return mIsFromStorage;
}
void setIsFromStorage(bool logged)
{
mIsFromStorage = logged;
}
// </FS:Ansariel>
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<LLNotificationPtr> mHistory;
};

View File

@ -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());
}

View File

@ -61,6 +61,7 @@ public:
Optional<void*> userdata;
Optional<LLSD> value; // state of checkbox, icon id/name, date
Optional<LLSD> alt_value;
Optional<std::string> label; // description or text
Optional<std::string> 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;

View File

@ -68,9 +68,10 @@ static LLDefaultChildRegistry::Register<LLScrollListCtrl> r("scroll_list");
// local structures & classes.
struct SortScrollListItem
{
SortScrollListItem(const std::vector<std::pair<S32, BOOL> >& sort_orders,const LLScrollListCtrl::sort_signal_t* sort_signal)
SortScrollListItem(const std::vector<std::pair<S32, BOOL> >& 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<std::pair<S32, BOOL> > 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),
// <FS:Ansariel> 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()
// <FS:Ansariel> Reset number of dynamic columns, too
mNumDynamicWidthColumns = 0;
dirtyColumns(); // Clears mColumnsIndexed
}
void LLScrollListCtrl::setColumnLabel(const std::string& column, const std::string& label)

View File

@ -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;

View File

@ -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)
{
}

View File

@ -55,6 +55,7 @@ public:
Optional<bool> enabled;
Optional<void*> userdata;
Optional<LLSD> value;
Optional<LLSD> 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<LLScrollListCell *> mColumns;
LLRect mRectangle;
};

View File

@ -1663,11 +1663,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;

View File

@ -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; // <FS:Ansariel> Check enabled state of button before executing!
LL_DEBUGS("UIUsage") << "button function name b -> " << commandp->executeFunctionName() << LL_ENDL;
// <FS:Ansariel> 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));

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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];

View File

@ -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;

View File

@ -43,10 +43,15 @@
#if LL_GTK
extern "C" {
# include "gtk/gtk.h"
#error "Direct use of GTK is deprecated"
}
#include <locale.h>
#endif // LL_GTK
#ifdef LL_GLIB
#include <glib.h>
#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<Atom, 3> 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) // <FS:LO> 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) // <FS:LO> 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; // <FS:ND/> 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; // <FS:ND/> 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()

View File

@ -220,6 +220,24 @@ private:
U32 mSDLSym; // <FS:ND/> Store the SDL Keysym too.
BOOL mUseLegacyCursors; // <FS:LO> 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;
};

View File

@ -1918,8 +1918,9 @@ void LLWindowWin32::initCursors(BOOL useLegacyCursors) // <FS:LO> 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) // <FS:LO> 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"));
/*<FS:LO> Legacy cursor setting from main program

View File

@ -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)

View File

@ -49,4 +49,3 @@ set(media_plugin_base_HEADER_FILES
add_library(media_plugin_base
${media_plugin_base_SOURCE_FILES}
)

View File

@ -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)

View File

@ -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*>((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:;
}
}

View File

@ -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,58 @@ 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;
// 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();
}
settings.disable_gpu = mDisableGPU;
#if LL_DARWIN
settings.disable_network_service = mDisableNetworkService;
@ -909,6 +988,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");

View File

@ -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)

View File

@ -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 <dbus/dbus-glib.h>
#include <stdio.h>
#include <gst/gst.h>
#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

View File

@ -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 <string>
#include <iostream>
#include <vector>
#ifdef LL_WINDOWS
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0502
#include <Windows.h>
#endif
#include "linden_common.h"
extern "C" {
#include <gst/gst.h>
#include <gst/app/gstappsink.h>
}
#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;
}

View File

@ -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 <vector>
extern "C" {
#include <gst/gst.h>
}
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)))

View File

@ -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 * )

View File

@ -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 <gst/gst.h>
#include <gst/app/gstappsink.h>
}
#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, &micro, &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
}
}

View File

@ -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
@ -2516,7 +2517,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}
@ -2536,6 +2537,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${LLPHYSICSEXTENSIONS_LIBRARIES}
${LLAPPEARANCE_LIBRARIES}
${GROWL_LIBRARY}
${GIO_LIBRARIES}
)
target_link_libraries(${VIEWER_BINARY_NAME} ${DISCORD_LIBRARY} )
@ -2563,26 +2565,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}
@ -2608,7 +2614,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}
@ -2859,8 +2864,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)

View File

@ -340,7 +340,7 @@
<string key="NSMaxSize">{10000000000000, 10000000000000}</string>
<string key="NSFrameAutosaveName">Second Life</string>
<int key="NSWindowCollectionBehavior">128</int>
<bool key="NSWindowIsRestorable">YES</bool>
<bool key="NSWindowIsRestorable">NO</bool>
</object>
<object class="NSWindowTemplate" id="979091056">
<int key="NSWindowStyleMask">31</int>

View File

@ -1 +1 @@
6.5.2
6.5.4

View File

@ -11121,7 +11121,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>PushToTalkToggle</key>
<map>
<key>Comment</key>
<string>Should the push-to-talk button behave as a toggle</string>
<string>Should the push-to-talk toolbar button behave as a toggle</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -11165,7 +11165,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>QAModeMetrics</key>
<map>
<key>Comment</key>
<string>"Enables QA features (logging, faster cycling) for metrics collector"</string>
<string>Enables QA features (logging, faster cycling) for metrics collector</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -11175,8 +11175,18 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Backup</key>
<integer>0</integer>
</map>
<key>QuitAfterSeconds</key>
<key>QAModeFakeSystemFolderIssues</key>
<map>
<key>Comment</key>
<string>Simulates system folder issues in inventory</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>QuitAfterSeconds</key>
<map>
<key>Comment</key>
<string>The duration allowed before quitting.</string>
@ -15697,6 +15707,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Backup</key>
<integer>0</integer>
</map>
<key>TextureFetchMinTimeToLog</key>
<map>
<key>Comment</key>
<string>If texture fetching time exceeds this value, texture fetch tester will log info</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>2.0</real>
</map>
<key>TextureFetchFakeFailureRate</key>
<map>
<key>Comment</key>
@ -15799,6 +15820,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Backup</key>
<integer>0</integer>
</map>
<key>TextureListFetchingThreshold</key>
<map>
<key>Comment</key>
<string>If the ratio between fetched and all textures in the list is greater than this threshold, which we assume that almost all textures are fetched</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0.97</real>
</map>
<key>TextureLoadFullRes</key>
<map>
<key>Comment</key>
@ -25901,6 +25933,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAutoTuneLock</key>
<map>
<key>Comment</key>
<string>When enabled the viewer will dynamically change settings until auto tune is explicitly turned off.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSAllowSelfImpostor</key>
@ -25980,6 +26023,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>FSUserTargetReflections</key>
<map>
<key>Comment</key>
<string>Set by auto tune floater on build</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>4</integer>
</map>
<key>FSReportRegionRestartToChat</key>
<map>
<key>Comment</key>

View File

@ -38,7 +38,7 @@ def munge_binding_redirect_version(src_manifest_name, src_config_name, dst_confi
comment = config_dom.createComment("This file is automatically generated by the build. see indra/newview/build_win32_appConfig.py")
config_dom.insertBefore(comment, config_dom.childNodes[0])
print "Writing: " + dst_config_name
print("Writing: " + dst_config_name)
f = open(dst_config_name, 'w')
config_dom.writexml(f)
f.close()

Binary file not shown.

Binary file not shown.

View File

@ -9,7 +9,7 @@ class FSViewerManifest:
def fs_splice_grid_substitution_strings( self, subst_strings ):
ret = subst_strings
if self.args.has_key( 'grid' ) and self.args['grid'] != None:
if 'grid' in self.args and self.args['grid'] != None:
ret[ 'grid' ] = self.args['grid']
ret[ 'grid_caps' ] = self.args['grid'].upper()
else:
@ -51,15 +51,15 @@ class FSViewerManifest:
stderr=subprocess.PIPE,stdout=subprocess.PIPE)
subprocess.check_call(["signtool.exe","sign","/n","Phoenix","/d","Firestorm","/du","http://www.phoenixviewer.com","/t","http://timestamp.verisign.com/scripts/timstamp.dll",self.args['configuration']+"\\"+self.final_exe()],
stderr=subprocess.PIPE,stdout=subprocess.PIPE)
except Exception, e:
print "Couldn't sign final binary. Tried to sign %s" % self.args['configuration']+"\\"+self.final_exe()
except Exception as e:
print("Couldn't sign final binary. Tried to sign %s" % self.args['configuration']+"\\"+self.final_exe())
def fs_sign_win_installer( self, substitution_strings ):
try:
subprocess.check_call(["signtool.exe","sign","/n","Phoenix","/d","Firestorm","/du","http://www.phoenixviewer.com",self.args['configuration']+"\\"+substitution_strings['installer_file']],stderr=subprocess.PIPE,stdout=subprocess.PIPE)
except Exception, e:
print "Working directory: %s" % os.getcwd()
print "Couldn't sign windows installer. Tried to sign %s" % self.args['configuration']+"\\"+substitution_strings['installer_file']
except Exception as e:
print("Working directory: %s" % os.getcwd())
print("Couldn't sign windows installer. Tried to sign %s" % self.args['configuration']+"\\"+substitution_strings['installer_file'])
def fs_delete_linux_symbols( self ):
debugDir = os.path.join( self.get_dst_prefix(), "bin", ".debug" )
@ -76,7 +76,7 @@ class FSViewerManifest:
def fs_save_linux_symbols( self ):
#AO: Try to package up symbols
# New Method, for reading cross platform stack traces on a linux/mac host
print( "Packaging symbols" )
print("Packaging symbols")
self.fs_save_symbols("linux")
@ -97,7 +97,7 @@ class FSViewerManifest:
], stderr=subprocess.PIPE,stdout=subprocess.PIPE )
pdbName = "firestorm-bin-public.pdb"
except:
print( "Cannot run pdbcopy, packaging private symbols" )
print("Cannot run pdbcopy, packaging private symbols")
# Store windows symbols we want to keep for debugging in a tar file, this will be later compressed with xz (lzma)
# Using tat+xz gives far superior compression than zip (~half the size of the zip archive).
@ -162,3 +162,63 @@ class FSViewerManifest:
if self.path( src,dst ) == 0:
self.missing.pop()
def fs_generate_breakpad_symbols_for_file( self, aFile ):
from os import makedirs, remove
from os.path import join, isfile
import subprocess
from shutil import move
dumpSym = join( self.args["build"], "..", "packages", "bin", "dump_syms" )
if not isfile( dumpSym ):
return
symbolFile = aFile +".sym"
with open( symbolFile, "w") as outfile:
subprocess.call( [dumpSym, aFile ], stdout=outfile )
firstline = open( symbolFile ).readline().strip()
if firstline != "":
module, os, bitness, hash, filename = firstline.split(" ")
symbolDir = join( "symbols", filename, hash )
try:
makedirs( symbolDir )
except:
pass
move( symbolFile, symbolDir )
if isfile( symbolFile ):
remove( symbolFile )
def fs_save_breakpad_symbols(self, osname):
from glob import glob
import sys
from os.path import isdir
from shutil import rmtree
import tarfile
if isdir( "symbols" ):
rmtree( "symbols" )
files = glob( "%s/bin/*" % self.args['dest'] )
for f in files:
self.fs_generate_breakpad_symbols_for_file( f )
files = glob( "%s/lib/*.so" % self.args['dest'] )
for f in files:
if f.find( "libcef.so" ) == -1:
self.fs_generate_breakpad_symbols_for_file( f )
if isdir( "symbols" ):
for a in self.args:
print("%s: %s" % (a, self.args[a]))
symbolsName = "%s/Phoenix_%s_%s_%s_symbols-%s-%d.tar.bz2" % (self.args['configuration'].lower(),
self.fs_channel_legacy_oneword(),
'-'.join( self.args['version'] ),
self.args['viewer_flavor'],
osname,
self.address_size)
fTar = tarfile.open( symbolsName, "w:bz2")
fTar.add("symbols", arcname=".")

View File

@ -51,8 +51,12 @@
#include "pipeline.h"
#include "llviewercontrol.h"
#include "fsavatarrenderpersistence.h"
#include "llpresetsmanager.h"
#include "fsperfstats.h" // <FS:Beq> performance stats support
#include "fslslbridge.h"
#include <llbutton.h>
extern F32 gSavedDrawDistance;
const F32 REFRESH_INTERVAL = 1.0f;
const S32 BAR_LEFT_PAD = 2;
@ -119,8 +123,11 @@ BOOL FSFloaterPerformance::postBuild()
auto tgt_panel = findChild<LLPanel>("target_subpanel");
if (tgt_panel)
{
tgt_panel->getChild<LLButton>("target_btn")->setCommitCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mAutoTunePanel));
tgt_panel->getChild<LLComboBox>("FSTuningFPSStrategy")->setCurrentByIndex(gSavedSettings.getU32("FSTuningFPSStrategy"));
tgt_panel->getChild<LLButton>("target_btn")->setCommitCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mAutoTunePanel));
tgt_panel->getChild<LLComboBox>("FSTuningFPSStrategy")->setCurrentByIndex(gSavedSettings.getU32("FSTuningFPSStrategy"));
tgt_panel->getChild<LLButton>("PrefSaveButton")->setCommitCallback(boost::bind(&FSFloaterPerformance::savePreset, this));
tgt_panel->getChild<LLButton>("PrefLoadButton")->setCommitCallback(boost::bind(&FSFloaterPerformance::loadPreset, this));
tgt_panel->getChild<LLButton>("Defaults")->setCommitCallback(boost::bind(&FSFloaterPerformance::setHardwareDefaults, this));
}
initBackBtn(mNearbyPanel);
@ -139,13 +146,14 @@ BOOL FSFloaterPerformance::postBuild()
mObjectList->setHoverIconName("StopReload_Off");
mObjectList->setIconClickedCallback(boost::bind(&FSFloaterPerformance::detachItem, this, _1));
mSettingsPanel->getChild<LLRadioGroup>("graphics_quality")->setCommitCallback(boost::bind(&FSFloaterPerformance::onChangeQuality, this, _2));
mSettingsPanel->getChild<LLSliderCtrl>("quality_vs_perf_selection")->setCommitCallback(boost::bind(&FSFloaterPerformance::onChangeQuality, this, _2));
mNearbyPanel->getChild<LLButton>("exceptions_btn")->setCommitCallback(boost::bind(&FSFloaterPerformance::onClickExceptions, this));
mNearbyPanel->getChild<LLCheckBoxCtrl>("hide_avatars")->setCommitCallback(boost::bind(&FSFloaterPerformance::onClickHideAvatars, this));
mNearbyPanel->getChild<LLCheckBoxCtrl>("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR));
mNearbyList = mNearbyPanel->getChild<LLNameListCtrl>("nearby_list");
mNearbyList->setRightMouseDownCallback(boost::bind(&FSFloaterPerformance::onAvatarListRightClick, this, _1, _2, _3));
updateComplexityText();
mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&FSFloaterPerformance::updateComplexityText, this));
@ -155,10 +163,53 @@ BOOL FSFloaterPerformance::postBuild()
mNearbyPanel->getChild<LLSliderCtrl>("FSRenderAvatarMaxART")->setCommitCallback(boost::bind(&FSFloaterPerformance::updateMaxRenderTime, this));
LLAvatarComplexityControls::setIndirectMaxArc();
// store the current setting as the users desired reflection detail and DD
gSavedSettings.setS32("FSUserTargetReflections", LLPipeline::RenderReflectionDetail);
if(!FSPerfStats::tunables.userAutoTuneEnabled)
{
if (gSavedDrawDistance)
{
gSavedSettings.setF32("FSAutoTuneRenderFarClipTarget", gSavedDrawDistance);
}
else
{
gSavedSettings.setF32("FSAutoTuneRenderFarClipTarget", LLPipeline::RenderFarClip);
}
}
return TRUE;
}
void FSFloaterPerformance::resetMaxArtSlider()
{
FSPerfStats::renderAvatarMaxART_ns = 0;
FSPerfStats::tunables.updateSettingsFromRenderCostLimit();
FSPerfStats::tunables.applyUpdates();
updateMaxRenderTime();
}
void FSFloaterPerformance::savePreset()
{
LLFloaterReg::showInstance("save_pref_preset", "graphic" );
}
void FSFloaterPerformance::loadPreset()
{
LLFloaterReg::showInstance("load_pref_preset", "graphic");
resetMaxArtSlider();
}
void FSFloaterPerformance::setHardwareDefaults()
{
LLFeatureManager::getInstance()->applyRecommendedSettings();
// reset indirects before refresh because we may have changed what they control
LLAvatarComplexityControls::setIndirectControls();
gSavedSettings.setString("PresetGraphicActive", "");
LLPresetsManager::getInstance()->triggerChangeSignal();
resetMaxArtSlider();
}
void FSFloaterPerformance::showSelectedPanel(LLPanel* selected_panel)
{
hidePanels();
@ -240,104 +291,111 @@ void FSFloaterPerformance::draw()
// tot_frame_time_ns -= tot_limit_time_ns;
// tot_frame_time_ns -= tot_sleep_time_ns;
if(tot_frame_time_ns == 0)
if(tot_frame_time_ns != 0)
{
LL_WARNS("performance") << "things went wrong, quit while we can." << LL_ENDL;
return;
}
auto pct_avatar_time = (tot_avatar_time_ns * 100)/tot_frame_time_ns;
auto pct_huds_time = (tot_huds_time_ns * 100)/tot_frame_time_ns;
auto pct_ui_time = (tot_ui_time_ns * 100)/tot_frame_time_ns;
auto pct_idle_time = (tot_idle_time_ns * 100)/tot_frame_time_ns;
auto pct_swap_time = (tot_swap_time_ns * 100)/tot_frame_time_ns;
auto pct_scene_render_time = (tot_scene_time_ns * 100)/tot_frame_time_ns;
pct_avatar_time = llclamp(pct_avatar_time,0.,100.);
pct_huds_time = llclamp(pct_huds_time,0.,100.);
pct_ui_time = llclamp(pct_ui_time,0.,100.);
pct_idle_time = llclamp(pct_idle_time,0.,100.);
pct_swap_time = llclamp(pct_swap_time,0.,100.);
pct_scene_render_time = llclamp(pct_scene_render_time,0.,100.);
auto pct_avatar_time = (tot_avatar_time_ns * 100)/tot_frame_time_ns;
auto pct_huds_time = (tot_huds_time_ns * 100)/tot_frame_time_ns;
auto pct_ui_time = (tot_ui_time_ns * 100)/tot_frame_time_ns;
auto pct_idle_time = (tot_idle_time_ns * 100)/tot_frame_time_ns;
auto pct_swap_time = (tot_swap_time_ns * 100)/tot_frame_time_ns;
auto pct_scene_render_time = (tot_scene_time_ns * 100)/tot_frame_time_ns;
pct_avatar_time = llclamp(pct_avatar_time,0.,100.);
pct_huds_time = llclamp(pct_huds_time,0.,100.);
pct_ui_time = llclamp(pct_ui_time,0.,100.);
pct_idle_time = llclamp(pct_idle_time,0.,100.);
pct_swap_time = llclamp(pct_swap_time,0.,100.);
pct_scene_render_time = llclamp(pct_scene_render_time,0.,100.);
args["AV_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_avatar_time));
args["HUDS_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_huds_time));
args["UI_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_ui_time));
args["IDLE_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_idle_time));
args["SWAP_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_swap_time));
args["SCENERY_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_scene_render_time));
args["TOT_FRAME_TIME"] = llformat("%02u", (U32)llround(tot_frame_time_ns/1000000));
args["FPSCAP"] = llformat("%02u", (U32)fpsCap);
args["FPSTARGET"] = llformat("%02u", (U32)targetFPS);
args["AV_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_avatar_time));
args["HUDS_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_huds_time));
args["UI_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_ui_time));
args["IDLE_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_idle_time));
args["SWAP_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_swap_time));
args["SCENERY_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_scene_render_time));
args["TOT_FRAME_TIME"] = llformat("%02u", (U32)llround(tot_frame_time_ns/1000000));
args["FPSCAP"] = llformat("%02u", (U32)fpsCap);
args["FPSTARGET"] = llformat("%02u", (U32)targetFPS);
getChild<LLTextBox>("av_frame_stats")->setText(getString("av_frame_pct", args));
getChild<LLTextBox>("huds_frame_stats")->setText(getString("huds_frame_pct", args));
getChild<LLTextBox>("frame_breakdown")->setText(getString("frame_stats", args));
auto textbox = getChild<LLTextBox>("fps_warning");
if (tot_sleep_time_raw > 0) // We are sleeping because view is not focussed
{
textbox->setVisible(true);
textbox->setText(getString("focus_fps"));
textbox->setColor(LLUIColorTable::instance().getColor("DrYellow"));
unreliable = true;
}
else if (tot_limit_time_raw > 0)
{
textbox->setVisible(true);
textbox->setText(getString("limit_fps", args));
textbox->setColor(LLUIColorTable::instance().getColor("DrYellow"));
unreliable = true;
}
else if (FSPerfStats::autoTune)
{
textbox->setVisible(true);
textbox->setText(getString("tuning_fps", args));
textbox->setColor(LLUIColorTable::instance().getColor("green"));
getChild<LLTextBox>("av_frame_stats")->setText(getString("av_frame_pct", args));
getChild<LLTextBox>("huds_frame_stats")->setText(getString("huds_frame_pct", args));
getChild<LLTextBox>("frame_breakdown")->setText(getString("frame_stats", args));
auto textbox = getChild<LLTextBox>("fps_warning");
if (tot_sleep_time_raw > 0) // We are sleeping because view is not focussed
{
textbox->setVisible(true);
textbox->setText(getString("focus_fps"));
textbox->setColor(LLUIColorTable::instance().getColor("DrYellow"));
unreliable = true;
}
else if (tot_limit_time_raw > 0)
{
textbox->setVisible(true);
textbox->setText(getString("limit_fps", args));
textbox->setColor(LLUIColorTable::instance().getColor("DrYellow"));
unreliable = true;
}
else if (FSPerfStats::tunables.userAutoTuneEnabled)
{
textbox->setVisible(true);
textbox->setText(getString("tuning_fps", args));
textbox->setColor(LLUIColorTable::instance().getColor("green"));
}
else
{
textbox->setVisible(false);
}
auto button = getChild<LLButton>("AutoTuneFPS");
if((bool)button->getToggleState() != FSPerfStats::tunables.userAutoTuneEnabled)
{
button->toggleState();
}
if (FSPerfStats::tunables.userAutoTuneEnabled && !unreliable )
{
// the tuning itself is managed from another thread but we can report progress here
// Is our target frame time lower than current? If so we need to take action to reduce draw overheads.
if (target_frame_time_ns <= tot_frame_time_ns)
{
U32 non_avatar_time_ns = tot_frame_time_ns - tot_avatar_time_ns;
// If the target frame time < non avatar frame time then we can pototentially reach it.
if (non_avatar_time_ns < target_frame_time_ns)
{
textbox->setColor(LLUIColorTable::instance().getColor("orange"));
}
else
{
// TODO(Beq): Set advisory text for further actions
textbox->setColor(LLUIColorTable::instance().getColor("red"));
}
}
else if (target_frame_time_ns > (tot_frame_time_ns + FSPerfStats::renderAvatarMaxART_ns))
{
// if we have more time to spare. Display this (the service will update things)
textbox->setColor(LLUIColorTable::instance().getColor("green"));
}
}
if (mHUDsPanel->getVisible())
{
populateHUDList();
}
else if (mNearbyPanel->getVisible())
{
populateNearbyList();
mNearbyPanel->getChild<LLCheckBoxCtrl>("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR));
}
else if (mComplexityPanel->getVisible())
{
populateObjectList();
}
}
else
{
textbox->setVisible(false);
LL_WARNS("performance") << "Scene time 0. Skipping til we have data." << LL_ENDL;
}
if (FSPerfStats::autoTune && !unreliable )
{
// the tuning itself is managed from another thread but we can report progress here
// Is our target frame time lower than current? If so we need to take action to reduce draw overheads.
if (target_frame_time_ns <= tot_frame_time_ns)
{
U32 non_avatar_time_ns = tot_frame_time_ns - tot_avatar_time_ns;
// If the target frame time < non avatar frame time then we can pototentially reach it.
if (non_avatar_time_ns < target_frame_time_ns)
{
textbox->setColor(LLUIColorTable::instance().getColor("orange"));
}
else
{
// TODO(Beq): Set advisory text for further actions
textbox->setColor(LLUIColorTable::instance().getColor("red"));
}
}
else if (target_frame_time_ns > (tot_frame_time_ns + FSPerfStats::renderAvatarMaxART_ns))
{
// if we have more time to spare. Display this (the service will update things)
textbox->setColor(LLUIColorTable::instance().getColor("green"));
}
}
if (mHUDsPanel->getVisible())
{
populateHUDList();
}
else if (mNearbyPanel->getVisible())
{
populateNearbyList();
mNearbyPanel->getChild<LLCheckBoxCtrl>("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR));
}
else if (mComplexityPanel->getVisible())
{
populateObjectList();
}
mUpdateTimer->setTimerExpirySec(REFRESH_INTERVAL);
}
LLFloater::draw();
@ -732,11 +790,9 @@ void FSFloaterPerformance::detachItem(const LLUUID& item_id)
void FSFloaterPerformance::onChangeQuality(const LLSD& data)
{
LLFloaterPreference* instance = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences");
if (instance)
{
instance->onChangeQuality(data);
}
U32 level = (U32)(data.asReal());
LLFeatureManager::getInstance()->setGraphicsLevel(level, true);
refresh();
}
void FSFloaterPerformance::onClickHideAvatars()

Some files were not shown because too many files have changed in this diff Show More