summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorAndreyL ProductEngine <alihatskiy@productengine.com>2019-03-01 02:28:15 +0200
committerAndreyL ProductEngine <alihatskiy@productengine.com>2019-03-01 02:28:15 +0200
commit27e197459da275d2cd8847aa36e6c6bc4720e5c5 (patch)
treefccc0ceaac90e03939d37e54cb8519a0132993cf /indra
parent1a1465dab94a2829cedb4ee4cd0c0169cea0fdeb (diff)
parent2ab914a9cdd1ad809879aca05dbf4b624949ecea (diff)
Merge
Diffstat (limited to 'indra')
-rw-r--r--indra/CMakeLists.txt1
-rw-r--r--indra/cmake/CMakeLists.txt1
-rw-r--r--indra/cmake/Copy3rdPartyLibs.cmake14
-rw-r--r--indra/cmake/LLAddBuildTest.cmake1
-rw-r--r--indra/cmake/LLBase.cmake4
-rw-r--r--indra/cmake/Linking.cmake1
-rw-r--r--indra/cmake/Requests.cmake7
-rw-r--r--indra/cmake/Variables.cmake3
-rw-r--r--indra/cmake/bugsplat.cmake25
-rw-r--r--indra/integration_tests/llimage_libtest/CMakeLists.txt2
-rwxr-xr-xindra/lib/python/indra/util/llmanifest.py271
-rw-r--r--indra/linux_crash_logger/CMakeLists.txt2
-rw-r--r--indra/llappearance/llavatarappearance.cpp4
-rw-r--r--indra/llappearance/llavatarappearance.h2
-rw-r--r--indra/llappearance/lllocaltextureobject.cpp1
-rw-r--r--indra/llcharacter/llcharacter.h2
-rw-r--r--indra/llcharacter/llkeyframemotion.cpp14
-rw-r--r--indra/llcommon/CMakeLists.txt7
-rw-r--r--indra/llcommon/llapp.cpp23
-rw-r--r--indra/llcommon/llapp.h3
-rw-r--r--indra/llcommon/llapr.cpp79
-rw-r--r--indra/llcommon/llapr.h85
-rw-r--r--indra/llcommon/llatomic.cpp28
-rw-r--r--indra/llcommon/llatomic.h69
-rw-r--r--indra/llcommon/llcoros.h20
-rw-r--r--indra/llcommon/llerror.cpp356
-rw-r--r--indra/llcommon/llerrorcontrol.h22
-rw-r--r--indra/llcommon/llevents.cpp23
-rw-r--r--indra/llcommon/llevents.h20
-rw-r--r--indra/llcommon/llfile.cpp19
-rw-r--r--indra/llcommon/llfixedbuffer.cpp2
-rw-r--r--indra/llcommon/llinitparam.h3
-rw-r--r--indra/llcommon/llinstancetracker.cpp7
-rw-r--r--indra/llcommon/llinstancetracker.h9
-rw-r--r--indra/llcommon/llleap.cpp51
-rw-r--r--indra/llcommon/llleap.h14
-rw-r--r--indra/llcommon/llmutex.cpp133
-rw-r--r--indra/llcommon/llmutex.h85
-rw-r--r--indra/llcommon/llpreprocessor.h23
-rw-r--r--indra/llcommon/llprocess.cpp27
-rw-r--r--indra/llcommon/llqueuedthread.h6
-rw-r--r--indra/llcommon/llrefcount.cpp109
-rw-r--r--indra/llcommon/llrefcount.h26
-rw-r--r--indra/llcommon/llstring.cpp153
-rw-r--r--indra/llcommon/llstring.h199
-rw-r--r--indra/llcommon/llsys.cpp24
-rw-r--r--indra/llcommon/llthread.cpp83
-rw-r--r--indra/llcommon/llthread.h12
-rw-r--r--indra/llcommon/llthreadsafequeue.cpp81
-rw-r--r--indra/llcommon/llthreadsafequeue.h135
-rw-r--r--indra/llcommon/lluuid.cpp2
-rw-r--r--indra/llcommon/llworkerthread.cpp4
-rw-r--r--indra/llcommon/llworkerthread.h2
-rw-r--r--indra/llcommon/stdtypes.h7
-rw-r--r--indra/llcommon/stringize.h52
-rw-r--r--indra/llcommon/tests/llerror_test.cpp96
-rw-r--r--indra/llcommon/tests/llleap_test.cpp7
-rw-r--r--indra/llcommon/tests/llprocess_test.cpp5
-rw-r--r--indra/llcommon/tests/llsdserialize_test.cpp7
-rw-r--r--indra/llcommon/tests/wrapllerrs.h14
-rw-r--r--indra/llcorehttp/_httpoprequest.cpp5
-rw-r--r--indra/llcorehttp/_httpservice.h2
-rw-r--r--indra/llcorehttp/_refcounted.h2
-rw-r--r--indra/llcorehttp/_thread.h1
-rw-r--r--indra/llcorehttp/httpcommon.cpp4
-rw-r--r--indra/llcorehttp/tests/test_httprequest.hpp14
-rw-r--r--indra/llcrashlogger/llcrashlock.cpp1
-rw-r--r--indra/llimage/llimage.cpp2
-rw-r--r--indra/llimage/llimageworker.cpp2
-rw-r--r--indra/llimagej2coj/CMakeLists.txt2
-rw-r--r--indra/llmath/llvolumemgr.cpp4
-rw-r--r--indra/llmessage/llbuffer.cpp2
-rw-r--r--indra/llmessage/llproxy.cpp2
-rw-r--r--indra/llmessage/llproxy.h2
-rw-r--r--indra/llmessage/llpumpio.cpp54
-rw-r--r--indra/llmessage/llpumpio.h11
-rw-r--r--indra/llmessage/tests/commtest.h8
-rw-r--r--indra/llmessage/tests/llhttpclient_test.cpp9
-rw-r--r--indra/llplugin/llpluginmessagepipe.cpp4
-rw-r--r--indra/llplugin/llpluginprocessparent.cpp4
-rw-r--r--indra/llplugin/slplugin/CMakeLists.txt2
-rw-r--r--indra/llprimitive/llmodel.h3
-rw-r--r--indra/llprimitive/llprimitive.cpp2
-rw-r--r--indra/llrender/llfontgl.cpp57
-rw-r--r--indra/llui/CMakeLists.txt1
-rw-r--r--indra/llui/llbutton.cpp4
-rw-r--r--indra/llui/llbutton.h7
-rw-r--r--indra/llui/llcheckboxctrl.h15
-rw-r--r--indra/llui/llcombobox.cpp36
-rw-r--r--indra/llui/lllayoutstack.cpp8
-rw-r--r--indra/llui/llmenugl.cpp4
-rw-r--r--indra/llui/llmenugl.h9
-rw-r--r--indra/llui/llnotificationslistener.cpp15
-rw-r--r--indra/llui/llsearchablecontrol.h71
-rw-r--r--indra/llui/llsliderctrl.h15
-rw-r--r--indra/llui/lltabcontainer.cpp60
-rw-r--r--indra/llui/lltabcontainer.h2
-rw-r--r--indra/llui/lltextbase.cpp11
-rw-r--r--indra/llui/lltextbase.h8
-rw-r--r--indra/llui/lltexteditor.cpp22
-rw-r--r--indra/llui/lluictrl.h1
-rw-r--r--indra/llvfs/lldir.cpp5
-rw-r--r--indra/llvfs/lldir_linux.cpp33
-rw-r--r--indra/llvfs/lldir_mac.cpp4
-rw-r--r--indra/llvfs/lldir_solaris.cpp60
-rw-r--r--indra/llvfs/lldir_win32.cpp111
-rw-r--r--indra/llvfs/lllfsthread.h1
-rw-r--r--indra/llvfs/llpidlock.cpp1
-rw-r--r--indra/llvfs/llvfs.cpp2
-rw-r--r--indra/llvfs/llvfsthread.h2
-rw-r--r--indra/llwindow/llopenglview-objc.mm4
-rw-r--r--indra/llwindow/llwindowmacosx.cpp10
-rw-r--r--indra/llwindow/llwindowwin32.cpp6
-rw-r--r--indra/llxml/llcontrol.cpp94
-rw-r--r--indra/llxml/llcontrol.h3
-rw-r--r--indra/llxml/tests/llcontrol_test.cpp39
-rw-r--r--indra/media_plugins/base/CMakeLists.txt2
-rw-r--r--indra/media_plugins/cef/CMakeLists.txt2
-rw-r--r--indra/media_plugins/example/CMakeLists.txt2
-rw-r--r--indra/media_plugins/gstreamer010/CMakeLists.txt2
-rw-r--r--indra/media_plugins/libvlc/CMakeLists.txt2
-rw-r--r--indra/newview/CMakeLists.txt356
-rw-r--r--indra/newview/Info-SecondLife.plist6
-rw-r--r--indra/newview/VIEWER_VERSION.txt2
-rw-r--r--indra/newview/app_settings/settings.xml34
-rw-r--r--indra/newview/installers/windows/installer_template.nsi234
-rw-r--r--indra/newview/installers/windows/lang_da.nsibin7816 -> 11760 bytes
-rwxr-xr-x[-rw-r--r--]indra/newview/installers/windows/lang_de.nsibin9850 -> 13014 bytes
-rw-r--r--indra/newview/installers/windows/lang_en-us.nsibin8734 -> 11488 bytes
-rwxr-xr-x[-rw-r--r--]indra/newview/installers/windows/lang_es.nsibin9872 -> 12744 bytes
-rwxr-xr-x[-rw-r--r--]indra/newview/installers/windows/lang_fr.nsibin10258 -> 13262 bytes
-rwxr-xr-x[-rw-r--r--]indra/newview/installers/windows/lang_it.nsibin9520 -> 12480 bytes
-rwxr-xr-x[-rw-r--r--]indra/newview/installers/windows/lang_ja.nsibin7204 -> 9644 bytes
-rw-r--r--indra/newview/installers/windows/lang_pl.nsibin8136 -> 12080 bytes
-rwxr-xr-x[-rw-r--r--]indra/newview/installers/windows/lang_pt-br.nsibin9864 -> 12892 bytes
-rwxr-xr-x[-rw-r--r--]indra/newview/installers/windows/lang_ru.nsibin9188 -> 12216 bytes
-rwxr-xr-x[-rw-r--r--]indra/newview/installers/windows/lang_tr.nsibin9286 -> 12126 bytes
-rwxr-xr-x[-rw-r--r--]indra/newview/installers/windows/lang_zh.nsibin6846 -> 9082 bytes
-rw-r--r--indra/newview/installers/windows/language_menu.nsibin1448 -> 1464 bytes
-rw-r--r--indra/newview/llappdelegate-objc.mm162
-rw-r--r--indra/newview/llappviewer.cpp105
-rw-r--r--indra/newview/llappviewer.h1
-rw-r--r--indra/newview/llappviewermacosx-for-objc.h53
-rw-r--r--indra/newview/llappviewermacosx.cpp150
-rw-r--r--indra/newview/llappviewermacosx.h4
-rw-r--r--indra/newview/llappviewerwin32.cpp157
-rw-r--r--indra/newview/llautoreplace.cpp7
-rw-r--r--indra/newview/llchatitemscontainerctrl.cpp2
-rw-r--r--indra/newview/llcontrolavatar.cpp2
-rw-r--r--indra/newview/llconversationmodel.cpp24
-rw-r--r--indra/newview/llconversationmodel.h4
-rw-r--r--indra/newview/llconversationview.cpp27
-rw-r--r--indra/newview/llconversationview.h1
-rw-r--r--indra/newview/lldirpicker.cpp2
-rw-r--r--indra/newview/llexternaleditor.cpp7
-rw-r--r--indra/newview/llfilepicker.cpp2
-rw-r--r--indra/newview/llfloateravatarpicker.cpp2
-rw-r--r--indra/newview/llfloaterconversationpreview.cpp2
-rw-r--r--indra/newview/llfloaterimcontainer.cpp104
-rw-r--r--indra/newview/llfloaterimcontainer.h4
-rw-r--r--indra/newview/llfloaterland.cpp2
-rw-r--r--indra/newview/llfloatermodelpreview.cpp7
-rw-r--r--indra/newview/llfloatermyscripts.cpp294
-rw-r--r--indra/newview/llfloatermyscripts.h60
-rw-r--r--indra/newview/llfloaterpreference.cpp213
-rw-r--r--indra/newview/llfloaterpreference.h16
-rw-r--r--indra/newview/llfloaterscriptlimits.cpp299
-rw-r--r--indra/newview/llfloaterscriptlimits.h47
-rw-r--r--indra/newview/llfloatertopobjects.cpp47
-rw-r--r--indra/newview/llfloatertopobjects.h11
-rw-r--r--indra/newview/llfloateruipreview.cpp28
-rw-r--r--indra/newview/llimprocessing.cpp32
-rw-r--r--indra/newview/llinventorybridge.cpp7
-rw-r--r--indra/newview/llinventorymodel.cpp16
-rw-r--r--indra/newview/llinventorypanel.cpp3
-rw-r--r--indra/newview/lllogchat.cpp145
-rw-r--r--indra/newview/lllogchat.h1
-rw-r--r--indra/newview/lllogininstance.cpp70
-rw-r--r--indra/newview/lllogininstance.h6
-rw-r--r--indra/newview/llmachineid.cpp35
-rw-r--r--indra/newview/llmainlooprepeater.cpp2
-rw-r--r--indra/newview/llmanip.cpp80
-rw-r--r--indra/newview/llmeshrepository.cpp75
-rw-r--r--indra/newview/llmoveview.cpp16
-rw-r--r--indra/newview/llmoveview.h2
-rw-r--r--indra/newview/llnotificationlistitem.cpp11
-rw-r--r--indra/newview/lloutfitslist.cpp21
-rw-r--r--indra/newview/lloutputmonitorctrl.cpp5
-rw-r--r--indra/newview/lloutputmonitorctrl.h6
-rw-r--r--indra/newview/llpanelclassified.cpp8
-rw-r--r--indra/newview/llpanelface.cpp5
-rw-r--r--indra/newview/llpanelgroupgeneral.cpp5
-rw-r--r--indra/newview/llpreviewnotecard.h16
-rw-r--r--indra/newview/llsearchableui.cpp160
-rw-r--r--indra/newview/llsearchableui.h121
-rw-r--r--indra/newview/llselectmgr.cpp40
-rw-r--r--indra/newview/llselectmgr.h2
-rw-r--r--indra/newview/llstartup.cpp3
-rw-r--r--indra/newview/llstatusbar.cpp92
-rw-r--r--indra/newview/llstatusbar.h17
-rw-r--r--indra/newview/lltexturecache.cpp16
-rw-r--r--indra/newview/lltexturecache.h2
-rw-r--r--indra/newview/lltexturectrl.cpp14
-rw-r--r--indra/newview/lltexturefetch.cpp6
-rw-r--r--indra/newview/lltexturefetch.h1
-rw-r--r--indra/newview/lltoastgroupnotifypanel.cpp16
-rw-r--r--indra/newview/lltoastnotifypanel.cpp8
-rw-r--r--indra/newview/lltoastpanel.cpp3
-rw-r--r--indra/newview/lltoastpanel.h1
-rw-r--r--indra/newview/lltoastscripttextbox.cpp4
-rw-r--r--indra/newview/lltool.cpp4
-rw-r--r--indra/newview/lltoolpie.cpp33
-rw-r--r--indra/newview/llversioninfo.cpp7
-rw-r--r--indra/newview/llviewercontrol.cpp6
-rw-r--r--indra/newview/llviewerfloaterreg.cpp2
-rw-r--r--indra/newview/llviewermedia.cpp45
-rw-r--r--indra/newview/llviewermenu.cpp18
-rw-r--r--indra/newview/llviewermenufile.cpp2
-rw-r--r--indra/newview/llviewermessage.cpp29
-rw-r--r--indra/newview/llviewerobject.cpp61
-rw-r--r--indra/newview/llviewerobject.h5
-rw-r--r--indra/newview/llviewerobjectlist.cpp2
-rw-r--r--indra/newview/llviewerparcelmgr.cpp147
-rw-r--r--indra/newview/llviewerparceloverlay.cpp17
-rw-r--r--indra/newview/llviewerparceloverlay.h2
-rw-r--r--indra/newview/llviewerregion.cpp19
-rw-r--r--indra/newview/llviewershadermgr.cpp3
-rw-r--r--indra/newview/llviewertexture.cpp138
-rw-r--r--indra/newview/llviewertexture.h7
-rw-r--r--indra/newview/llviewerwindow.cpp5
-rw-r--r--indra/newview/llvoavatar.cpp4
-rw-r--r--indra/newview/llvoavatar.h2
-rw-r--r--indra/newview/llvoicevivox.cpp9
-rw-r--r--indra/newview/llvovolume.cpp29
-rw-r--r--indra/newview/llvovolume.h2
-rw-r--r--indra/newview/llvowlsky.cpp3
-rw-r--r--indra/newview/llwatchdog.cpp4
-rw-r--r--indra/newview/llwebprofile.cpp4
-rw-r--r--indra/newview/llworldmapview.cpp15
-rw-r--r--indra/newview/llxmlrpctransaction.cpp32
-rw-r--r--indra/newview/skins/default/default_languages.xml39
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_general.xml1
-rw-r--r--indra/newview/skins/default/xui/de/floater_pathfinding_console.xml2
-rw-r--r--indra/newview/skins/default/xui/de/floater_pathfinding_linksets.xml8
-rw-r--r--indra/newview/skins/default/xui/de/notifications.xml36
-rw-r--r--indra/newview/skins/default/xui/de/panel_preferences_general.xml1
-rw-r--r--indra/newview/skins/default/xui/de/strings.xml21
-rw-r--r--indra/newview/skins/default/xui/en/floater_bulk_perms.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_model_preview.xml29
-rw-r--r--indra/newview/skins/default/xui/en/floater_my_scripts.xml22
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences.xml42
-rw-r--r--indra/newview/skins/default/xui/en/floater_tools.xml24
-rw-r--r--indra/newview/skins/default/xui/en/floater_top_objects.xml28
-rw-r--r--indra/newview/skins/default/xui/en/fonts.xml2
-rw-r--r--indra/newview/skins/default/xui/en/language_settings.xml1
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml7
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml89
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_general.xml5
-rw-r--r--indra/newview/skins/default/xui/en/panel_status_bar.xml40
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_item_info.xml20
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_task_info.xml44
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml35
-rw-r--r--indra/newview/skins/default/xui/es/notifications.xml35
-rw-r--r--indra/newview/skins/default/xui/es/panel_preferences_general.xml1
-rw-r--r--indra/newview/skins/default/xui/es/strings.xml21
-rw-r--r--indra/newview/skins/default/xui/fr/notifications.xml36
-rw-r--r--indra/newview/skins/default/xui/fr/panel_preferences_general.xml1
-rw-r--r--indra/newview/skins/default/xui/fr/strings.xml21
-rw-r--r--indra/newview/skins/default/xui/it/notifications.xml34
-rw-r--r--indra/newview/skins/default/xui/it/panel_preferences_general.xml1
-rw-r--r--indra/newview/skins/default/xui/it/strings.xml21
-rw-r--r--indra/newview/skins/default/xui/ja/notifications.xml34
-rw-r--r--indra/newview/skins/default/xui/ja/panel_preferences_general.xml1
-rw-r--r--indra/newview/skins/default/xui/ja/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/strings.xml21
-rw-r--r--indra/newview/skins/default/xui/pl/panel_preferences_general.xml1
-rw-r--r--indra/newview/skins/default/xui/pt/notifications.xml36
-rw-r--r--indra/newview/skins/default/xui/pt/panel_preferences_general.xml1
-rw-r--r--indra/newview/skins/default/xui/pt/strings.xml21
-rw-r--r--indra/newview/skins/default/xui/ru/notifications.xml36
-rw-r--r--indra/newview/skins/default/xui/ru/panel_preferences_general.xml1
-rw-r--r--indra/newview/skins/default/xui/ru/strings.xml21
-rw-r--r--indra/newview/skins/default/xui/tr/notifications.xml36
-rw-r--r--indra/newview/skins/default/xui/tr/panel_preferences_general.xml1
-rw-r--r--indra/newview/skins/default/xui/tr/strings.xml21
-rw-r--r--indra/newview/skins/default/xui/zh/floater_tos.xml2
-rw-r--r--indra/newview/skins/default/xui/zh/notifications.xml32
-rw-r--r--indra/newview/skins/default/xui/zh/panel_preferences_general.xml1
-rw-r--r--indra/newview/skins/default/xui/zh/strings.xml21
-rw-r--r--indra/newview/tests/llversioninfo_test.cpp6
-rwxr-xr-xindra/newview/viewer_manifest.py1040
-rw-r--r--indra/test/test.cpp1
-rw-r--r--indra/viewer_components/login/lllogin.cpp56
-rw-r--r--indra/win_crash_logger/CMakeLists.txt1
294 files changed, 6102 insertions, 3531 deletions
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index a40b2c0846..6c20a813ba 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -44,6 +44,7 @@ if (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts)
endif (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts)
add_custom_target(viewer)
+
add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger)
add_subdirectory(${LIBS_OPEN_PREFIX}llplugin)
add_subdirectory(${LIBS_OPEN_PREFIX}llui)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 4a3ebe4835..84e1c5d6fd 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -12,6 +12,7 @@ set(cmake_SOURCE_FILES
Audio.cmake
BerkeleyDB.cmake
Boost.cmake
+ bugsplat.cmake
BuildVersion.cmake
CEFPlugin.cmake
CEFPlugin.cmake
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 09a97fc03e..dde53835fb 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -49,6 +49,20 @@ if(WINDOWS)
libhunspell.dll
)
+ # Filenames are different for 32/64 bit BugSplat file and we don't
+ # have any control over them so need to branch.
+ if (BUGSPLAT_DB)
+ if(ADDRESS_SIZE EQUAL 32)
+ set(release_files ${release_files} BugSplat.dll)
+ set(release_files ${release_files} BugSplatRc.dll)
+ set(release_files ${release_files} BsSndRpt.exe)
+ else(ADDRESS_SIZE EQUAL 32)
+ set(release_files ${release_files} BugSplat64.dll)
+ set(release_files ${release_files} BugSplatRc64.dll)
+ set(release_files ${release_files} BsSndRpt64.exe)
+ endif(ADDRESS_SIZE EQUAL 32)
+ endif (BUGSPLAT_DB)
+
if (FMODEX)
if(ADDRESS_SIZE EQUAL 32)
diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake
index 024bfe14a1..b3f42c1a5e 100644
--- a/indra/cmake/LLAddBuildTest.cmake
+++ b/indra/cmake/LLAddBuildTest.cmake
@@ -1,4 +1,5 @@
# -*- cmake -*-
+include(00-Common)
include(LLTestCommand)
include(GoogleMock)
include(Tut)
diff --git a/indra/cmake/LLBase.cmake b/indra/cmake/LLBase.cmake
deleted file mode 100644
index 76e3c688a3..0000000000
--- a/indra/cmake/LLBase.cmake
+++ /dev/null
@@ -1,4 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-use_prebuilt_binary(llbase)
diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake
index 74fe3f1137..3cb235a9d5 100644
--- a/indra/cmake/Linking.cmake
+++ b/indra/cmake/Linking.cmake
@@ -66,6 +66,7 @@ if (WINDOWS)
wldap32
gdi32
user32
+ ole32
dbghelp
)
else (WINDOWS)
diff --git a/indra/cmake/Requests.cmake b/indra/cmake/Requests.cmake
deleted file mode 100644
index b9c729d697..0000000000
--- a/indra/cmake/Requests.cmake
+++ /dev/null
@@ -1,7 +0,0 @@
-if (DARWIN)
- include (Prebuilt)
- use_prebuilt_binary(requests)
- use_prebuilt_binary(urllib3)
- use_prebuilt_binary(chardet)
- use_prebuilt_binary(idna)
-endif (DARWIN)
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index bd69c49856..2b54cd4155 100644
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -33,6 +33,8 @@ set(INTEGRATION_TESTS_PREFIX)
set(LL_TESTS ON CACHE BOOL "Build and run unit and integration tests (disable for build timing runs to reduce variation")
set(INCREMENTAL_LINK OFF CACHE BOOL "Use incremental linking on win32 builds (enable for faster links on some machines)")
set(ENABLE_MEDIA_PLUGINS ON CACHE BOOL "Turn off building media plugins if they are imported by third-party library mechanism")
+set(VIEWER_SYMBOL_FILE "" CACHE STRING "Name of tarball into which to place symbol files")
+set(BUGSPLAT_DB "" CACHE STRING "BugSplat database name, if BugSplat crash reporting is desired")
if(LIBS_CLOSED_DIR)
file(TO_CMAKE_PATH "${LIBS_CLOSED_DIR}" LIBS_CLOSED_DIR)
@@ -209,7 +211,6 @@ set(SIGNING_IDENTITY "" CACHE STRING "Specifies the signing identity to use, if
set(VERSION_BUILD "0" CACHE STRING "Revision number passed in from the outside")
set(USESYSTEMLIBS OFF CACHE BOOL "Use libraries from your system rather than Linden-supplied prebuilt libraries.")
-set(UNATTENDED OFF CACHE BOOL "Should be set to ON for building with VC Express editions.")
set(USE_PRECOMPILED_HEADERS ON CACHE BOOL "Enable use of precompiled header directives where supported.")
diff --git a/indra/cmake/bugsplat.cmake b/indra/cmake/bugsplat.cmake
new file mode 100644
index 0000000000..59644b73ce
--- /dev/null
+++ b/indra/cmake/bugsplat.cmake
@@ -0,0 +1,25 @@
+# BugSplat is engaged by setting BUGSPLAT_DB to the target BugSplat database
+# name.
+if (BUGSPLAT_DB)
+ if (USESYSTEMLIBS)
+ message(STATUS "Looking for system BugSplat")
+ set(BUGSPLAT_FIND_QUIETLY ON)
+ set(BUGSPLAT_FIND_REQUIRED ON)
+ include(FindBUGSPLAT)
+ else (USESYSTEMLIBS)
+ message(STATUS "Engaging autobuild BugSplat")
+ include(Prebuilt)
+ use_prebuilt_binary(bugsplat)
+ if (WINDOWS)
+ set(BUGSPLAT_LIBRARIES
+ ${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib
+ )
+ elseif (DARWIN)
+ find_library(BUGSPLAT_LIBRARIES BugsplatMac
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}")
+ else (WINDOWS)
+
+ endif (WINDOWS)
+ set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/bugsplat)
+ endif (USESYSTEMLIBS)
+endif (BUGSPLAT_DB)
diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt
index 13cf1f7bde..d9353f904c 100644
--- a/indra/integration_tests/llimage_libtest/CMakeLists.txt
+++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt
@@ -40,7 +40,7 @@ add_executable(llimage_libtest
WIN32
MACOSX_BUNDLE
${llimage_libtest_SOURCE_FILES}
-)
+ )
set_target_properties(llimage_libtest
PROPERTIES
diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py
index 598261e3d7..2e6cf53912 100755
--- a/indra/lib/python/indra/util/llmanifest.py
+++ b/indra/lib/python/indra/util/llmanifest.py
@@ -33,13 +33,14 @@ import filecmp
import fnmatch
import getopt
import glob
+import itertools
+import operator
import os
import re
import shutil
+import subprocess
import sys
import tarfile
-import errno
-import subprocess
class ManifestError(RuntimeError):
"""Use an exception more specific than generic Python RuntimeError"""
@@ -49,7 +50,9 @@ class ManifestError(RuntimeError):
class MissingError(ManifestError):
"""You specified a file that doesn't exist"""
- pass
+ def __init__(self, msg):
+ self.msg = msg
+ super(MissingError, self).__init__(self.msg)
def path_ancestors(path):
drive, path = os.path.splitdrive(os.path.normpath(path))
@@ -90,7 +93,7 @@ DEFAULT_SRCTREE = os.path.dirname(sys.argv[0])
CHANNEL_VENDOR_BASE = 'Second Life'
RELEASE_CHANNEL = CHANNEL_VENDOR_BASE + ' Release'
-ARGUMENTS=[
+BASE_ARGUMENTS=[
dict(name='actions',
description="""This argument specifies the actions that are to be taken when the
script is run. The meaningful actions are currently:
@@ -108,8 +111,19 @@ ARGUMENTS=[
Example use: %(name)s --arch=i686
On Linux this would try to use Linux_i686Manifest.""",
default=""),
+ dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE),
dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE),
dict(name='buildtype', description='Build type (i.e. Debug, Release, RelWithDebInfo).', default=None),
+ dict(name='bundleid',
+ description="""The Mac OS X Bundle identifier.""",
+ default="com.secondlife.indra.viewer"),
+ dict(name='channel',
+ description="""The channel to use for updates, packaging, settings name, etc.""",
+ default='CHANNEL UNSET'),
+ dict(name='channel_suffix',
+ description="""Addition to the channel for packaging and channel value,
+ but not application name (used internally)""",
+ default=None),
dict(name='configuration',
description="""The build configuration used.""",
default="Release"),
@@ -117,12 +131,6 @@ ARGUMENTS=[
dict(name='grid',
description="""Which grid the client will try to connect to.""",
default=None),
- dict(name='channel',
- description="""The channel to use for updates, packaging, settings name, etc.""",
- default='CHANNEL UNSET'),
- dict(name='channel_suffix',
- description="""Addition to the channel for packaging and channel value, but not application name (used internally)""",
- default=None),
dict(name='installer_name',
description=""" The name of the file that the installer should be
packaged up into. Only used on Linux at the moment.""",
@@ -134,10 +142,14 @@ ARGUMENTS=[
description="""The current platform, to be used for looking up which
manifest class to run.""",
default=get_default_platform),
+ dict(name='signature',
+ description="""This specifies an identity to sign the viewer with, if any.
+ If no value is supplied, the default signature will be used, if any. Currently
+ only used on Mac OS X.""",
+ default=None),
dict(name='source',
description='Source directory.',
default=DEFAULT_SRCTREE),
- dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE),
dict(name='touch',
description="""File to touch when action is finished. Touch file will
contain the name of the final package in a form suitable
@@ -145,23 +157,15 @@ ARGUMENTS=[
default=None),
dict(name='versionfile',
description="""The name of a file containing the full version number."""),
- dict(name='bundleid',
- description="""The Mac OS X Bundle identifier.""",
- default="com.secondlife.indra.viewer"),
- dict(name='signature',
- description="""This specifies an identity to sign the viewer with, if any.
- If no value is supplied, the default signature will be used, if any. Currently
- only used on Mac OS X.""",
- default=None)
]
-def usage(srctree=""):
+def usage(arguments, srctree=""):
nd = {'name':sys.argv[0]}
print """Usage:
%(name)s [options] [destdir]
Options:
""" % nd
- for arg in ARGUMENTS:
+ for arg in arguments:
default = arg['default']
if hasattr(default, '__call__'):
default = "(computed value) \"" + str(default(srctree)) + '"'
@@ -172,11 +176,15 @@ def usage(srctree=""):
default,
arg['description'] % nd)
-def main():
-## import itertools
+def main(extra=[]):
## print ' '.join((("'%s'" % item) if ' ' in item else item)
## for item in itertools.chain([sys.executable], sys.argv))
- option_names = [arg['name'] + '=' for arg in ARGUMENTS]
+ # Supplement our default command-line switches with any desired by
+ # application-specific caller.
+ arguments = list(itertools.chain(BASE_ARGUMENTS, extra))
+ # Alphabetize them by option name in case we display usage.
+ arguments.sort(key=operator.itemgetter('name'))
+ option_names = [arg['name'] + '=' for arg in arguments]
option_names.append('help')
options, remainder = getopt.getopt(sys.argv[1:], "", option_names)
@@ -199,11 +207,11 @@ def main():
# early out for help
if 'help' in args:
# *TODO: it is a huge hack to pass around the srctree like this
- usage(args['source'])
+ usage(arguments, srctree=args['source'])
return
# defaults
- for arg in ARGUMENTS:
+ for arg in arguments:
if arg['name'] not in args:
default = arg['default']
if hasattr(default, '__call__'):
@@ -232,104 +240,68 @@ def main():
print "Option:", opt, "=", args[opt]
# pass in sourceid as an argument now instead of an environment variable
- try:
- args['sourceid'] = os.environ["sourceid"]
- except KeyError:
- args['sourceid'] = ""
+ args['sourceid'] = os.environ.get("sourceid", "")
# Build base package.
touch = args.get('touch')
if touch:
- print 'Creating base package'
- args['package_id'] = "" # base package has no package ID
+ print '================ Creating base package'
+ else:
+ 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'
# handle multiple packages if set
- try:
- additional_packages = os.environ["additional_packages"]
- except KeyError:
- additional_packages = ""
+ # ''.split() produces empty list
+ additional_packages = os.environ.get("additional_packages", "").split()
if additional_packages:
# Determine destination prefix / suffix for additional packages.
- base_dest_postfix = args['dest']
- base_dest_prefix = ""
- base_dest_parts = args['dest'].split(os.sep)
- if len(base_dest_parts) > 1:
- base_dest_postfix = base_dest_parts[len(base_dest_parts) - 1]
- base_dest_prefix = base_dest_parts[0]
- i = 1
- while i < len(base_dest_parts) - 1:
- base_dest_prefix = base_dest_prefix + os.sep + base_dest_parts[i]
- i = i + 1
+ base_dest_parts = list(os.path.split(args['dest']))
+ base_dest_parts.insert(-1, "{}")
+ base_dest_template = os.path.join(*base_dest_parts)
# Determine touched prefix / suffix for additional packages.
- base_touch_postfix = ""
- base_touch_prefix = ""
if touch:
- base_touch_postfix = touch
- base_touch_parts = touch.split('/')
+ base_touch_parts = list(os.path.split(touch))
+ # Because of the special insert() logic below, we don't just want
+ # [dirpath, basename]; we want [dirpath, directory, basename].
+ # Further split the dirpath and replace it in the list.
+ base_touch_parts[0:1] = os.path.split(base_touch_parts[0])
if "arwin" in args['platform']:
- if len(base_touch_parts) > 1:
- base_touch_postfix = base_touch_parts[len(base_touch_parts) - 1]
- base_touch_prefix = base_touch_parts[0]
- i = 1
- while i < len(base_touch_parts) - 1:
- base_touch_prefix = base_touch_prefix + '/' + base_touch_parts[i]
- i = i + 1
+ base_touch_parts.insert(-1, "{}")
else:
- if len(base_touch_parts) > 2:
- base_touch_postfix = base_touch_parts[len(base_touch_parts) - 2] + '/' + base_touch_parts[len(base_touch_parts) - 1]
- base_touch_prefix = base_touch_parts[0]
- i = 1
- while i < len(base_touch_parts) - 2:
- base_touch_prefix = base_touch_prefix + '/' + base_touch_parts[i]
- i = i + 1
- # Store base channel name.
- base_channel_name = args['channel']
- # Build each additional package.
- package_id_list = additional_packages.split(" ")
- args['channel'] = base_channel_name
- for package_id in package_id_list:
- try:
- if package_id + "_viewer_channel_suffix" in os.environ:
- args['channel_suffix'] = os.environ[package_id + "_viewer_channel_suffix"]
- else:
- args['channel_suffix'] = None
- if package_id + "_sourceid" in os.environ:
- args['sourceid'] = os.environ[package_id + "_sourceid"]
- else:
- args['sourceid'] = None
- args['dest'] = base_dest_prefix + os.sep + package_id + os.sep + base_dest_postfix
- except KeyError:
- sys.stderr.write("Failed to create package for package_id: %s" % package_id)
- sys.stderr.flush()
- continue
+ base_touch_parts.insert(-2, "{}")
+ base_touch_template = os.path.join(*base_touch_parts)
+ for package_id in additional_packages:
+ args['channel_suffix'] = os.environ.get(package_id + "_viewer_channel_suffix")
+ 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']
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
- faketouch = base_touch_prefix + '/' + package_id + '/' + base_touch_postfix
- fp = open(faketouch, 'w')
- fp.write('set package_file=%s\n' % wm.package_file)
- fp.close()
-
+ 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']
# 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...
- touch = args.get('touch')
if touch:
- fp = open(touch, 'w')
- fp.write('set package_file=%s\n' % base_package_file)
- fp.close()
+ with open(touch, 'w') as fp:
+ fp.write('set package_file=%s\n' % base_package_file)
print 'touched', touch
return 0
@@ -375,7 +347,7 @@ class LLManifest(object):
in the file list by path()."""
self.excludes.append(glob)
- def prefix(self, src='', build=None, dst=None):
+ def prefix(self, src='', build='', dst='', src_dst=None):
"""
Usage:
@@ -385,8 +357,21 @@ class LLManifest(object):
For the duration of the 'with' block, pushes a prefix onto the stack.
Within that block, all relevant method calls (esp. to path()) will
prefix paths with the entire prefix stack. Source and destination
- prefixes can be different, though if only one is provided they are
- both equal. To specify a no-op, use an empty string, not None.
+ prefixes are independent; if omitted (or passed as the empty string),
+ the prefix has no effect. Thus:
+
+ with self.prefix(src='foo'):
+ # no effect on dst
+
+ with self.prefix(dst='bar'):
+ # no effect on src
+
+ If you want to set both at once, use src_dst:
+
+ with self.prefix(src_dst='subdir'):
+ # same as self.prefix(src='subdir', dst='subdir')
+ # Passing src_dst makes any src or dst argument in the same
+ # parameter list irrelevant.
Also supports the older (pre-Python-2.5) syntax:
@@ -400,34 +385,42 @@ class LLManifest(object):
returned True specifically so that the caller could indent the
relevant block of code with 'if', just for aesthetic purposes.
"""
- if dst is None:
- dst = src
- if build is None:
- build = src
+ if src_dst is not None:
+ src = src_dst
+ dst = src_dst
self.src_prefix.append(src)
self.artwork_prefix.append(src)
self.build_prefix.append(build)
self.dst_prefix.append(dst)
+## self.display_stacks()
+
# The above code is unchanged from the original implementation. What's
# new is the return value. We're going to return an instance of
# PrefixManager that binds this LLManifest instance and Does The Right
# Thing on exit.
return self.PrefixManager(self)
+ 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)))
+
class PrefixManager(object):
+ # stack attributes we manage in this LLManifest (sub)class
+ # instance
+ stacks = ("src_prefix", "artwork_prefix", "build_prefix", "dst_prefix")
+
def __init__(self, manifest):
self.manifest = manifest
- # stack attributes we manage in this LLManifest (sub)class
- # instance
- stacks = ("src_prefix", "artwork_prefix", "build_prefix", "dst_prefix")
# If the caller wrote:
# with self.prefix(...):
# as intended, then bind the state of each prefix stack as it was
# just BEFORE the call to prefix(). Since prefix() appended an
# entry to each prefix stack, capture len()-1.
self.prevlen = { stack: len(getattr(self.manifest, stack)) - 1
- for stack in stacks }
+ for stack in self.stacks }
def __nonzero__(self):
# If the caller wrote:
@@ -460,6 +453,8 @@ class LLManifest(object):
# truncate that list back to 'prevlen'
del getattr(self.manifest, stack)[prevlen:]
+## self.manifest.display_stacks()
+
def end_prefix(self, descr=None):
"""Pops a prefix off the stack. If given an argument, checks
the argument against the top of the stack. If the argument
@@ -505,6 +500,19 @@ class LLManifest(object):
relative to the destination directory."""
return os.path.join(self.get_dst_prefix(), relpath)
+ def _relative_dst_path(self, dstpath):
+ """
+ Returns the path to a file or directory relative to the destination directory.
+ This should only be used for generating diagnostic output in the path method.
+ """
+ dest_root=self.dst_prefix[0]
+ if dstpath.startswith(dest_root+os.path.sep):
+ return dstpath[len(dest_root)+1:]
+ elif dstpath.startswith(dest_root):
+ return dstpath[len(dest_root):]
+ else:
+ return dstpath
+
def ensure_src_dir(self, reldir):
"""Construct the path for a directory relative to the
source path, and ensures that it exists. Returns the
@@ -607,9 +615,16 @@ class LLManifest(object):
# *TODO is this gonna be useful?
print "Cleaning up " + c
+ def process_either(self, src, dst):
+ # If it's a real directory, recurse through it --
+ # but not a symlink! Handle those like files.
+ if os.path.isdir(src) and not os.path.islink(src):
+ return self.process_directory(src, dst)
+ else:
+ return self.process_file(src, dst)
+
def process_file(self, src, dst):
if self.includes(src, dst):
-# print src, "=>", dst
for action in self.actions:
methodname = action + "_action"
method = getattr(self, methodname, None)
@@ -634,10 +649,7 @@ class LLManifest(object):
for name in names:
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
- if os.path.isdir(srcname):
- count += self.process_directory(srcname, dstname)
- else:
- count += self.process_file(srcname, dstname)
+ count += self.process_either(srcname, dstname)
return count
def includes(self, src, dst):
@@ -677,7 +689,11 @@ class LLManifest(object):
# Don't recopy file if it's up-to-date.
# If we seem to be not not overwriting files that have been
# updated, set the last arg to False, but it will take longer.
+## reldst = (dst[len(self.dst_prefix[0]):]
+## if dst.startswith(self.dst_prefix[0])
+## else dst).lstrip(r'\/')
if os.path.exists(dst) and filecmp.cmp(src, dst, True):
+## print "{} (skipping, {} exists)".format(src, reldst)
return
# only copy if it's not excluded
if self.includes(src, dst):
@@ -687,6 +703,7 @@ class LLManifest(object):
if err.errno != errno.ENOENT:
raise
+## print "{} => {}".format(src, reldst)
shutil.copy2(src, dst)
def ccopytree(self, src, dst):
@@ -785,13 +802,13 @@ class LLManifest(object):
return self.path(os.path.join(path, file), file)
def path(self, src, dst=None):
- sys.stdout.write("Processing %s => %s ... " % (src, dst))
sys.stdout.flush()
if src == None:
raise ManifestError("No source file, dst is " + dst)
if dst == None:
dst = src
dst = os.path.join(self.get_dst_prefix(), dst)
+ sys.stdout.write("Processing %s => %s ... " % (src, self._relative_dst_path(dst)))
def try_path(src):
# expand globs
@@ -804,29 +821,21 @@ class LLManifest(object):
# if we're specifying a single path (not a glob),
# we should error out if it doesn't exist
self.check_file_exists(src)
- # if it's a directory, recurse through it
- if os.path.isdir(src):
- count += self.process_directory(src, dst)
- else:
- count += self.process_file(src, dst)
+ count += self.process_either(src, dst)
return count
- for pfx in self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix():
+ try_prefixes = [self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix()]
+ tried=[]
+ count=0
+ while not count and try_prefixes:
+ pfx = try_prefixes.pop(0)
try:
count = try_path(os.path.join(pfx, src))
except MissingError:
- # If src isn't a wildcard, and if that file doesn't exist in
- # this pfx, try next pfx.
- count = 0
- continue
-
- # Here try_path() didn't raise MissingError. Did it process any files?
- if count:
- break
- # Even though try_path() didn't raise MissingError, it returned 0
- # files. src is probably a wildcard meant for some other pfx. Loop
- # back to try the next.
-
+ tried.append(pfx)
+ if not try_prefixes:
+ # no more prefixes left to try
+ print "unable to find '%s'; looked in:\n %s" % (src, '\n '.join(tried))
print "%d files" % count
# Let caller check whether we processed as many files as expected. In
diff --git a/indra/linux_crash_logger/CMakeLists.txt b/indra/linux_crash_logger/CMakeLists.txt
index 029096df37..315aed8d11 100644
--- a/indra/linux_crash_logger/CMakeLists.txt
+++ b/indra/linux_crash_logger/CMakeLists.txt
@@ -78,4 +78,4 @@ target_link_libraries(linux-crash-logger
)
add_custom_target(linux-crash-logger-target ALL
- DEPENDS linux-crash-logger)
+ DEPENDS linux-crash-logger)
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index 92217c60ff..38cda2e2f1 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -1348,9 +1348,9 @@ LLVector3 LLAvatarAppearance::getVolumePos(S32 joint_index, LLVector3& volume_of
//-----------------------------------------------------------------------------
// findCollisionVolume()
//-----------------------------------------------------------------------------
-LLJoint* LLAvatarAppearance::findCollisionVolume(U32 volume_id)
+LLJoint* LLAvatarAppearance::findCollisionVolume(S32 volume_id)
{
- if ((S32)volume_id > mNumCollisionVolumes)
+ if ((volume_id < 0) || (volume_id >= mNumCollisionVolumes))
{
return NULL;
}
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index 7815c1844b..6a4dbf3726 100644
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -93,7 +93,7 @@ public:
/*virtual*/ const char* getAnimationPrefix() { return "avatar"; }
/*virtual*/ LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset);
- /*virtual*/ LLJoint* findCollisionVolume(U32 volume_id);
+ /*virtual*/ LLJoint* findCollisionVolume(S32 volume_id);
/*virtual*/ S32 getCollisionVolumeID(std::string &name);
/*virtual*/ LLPolyMesh* getHeadMesh();
/*virtual*/ LLPolyMesh* getUpperBodyMesh();
diff --git a/indra/llappearance/lllocaltextureobject.cpp b/indra/llappearance/lllocaltextureobject.cpp
index f49cf21512..3f564ec3de 100644
--- a/indra/llappearance/lllocaltextureobject.cpp
+++ b/indra/llappearance/lllocaltextureobject.cpp
@@ -210,4 +210,3 @@ void LLLocalTextureObject::setBakedReady(BOOL ready)
{
mIsBakedReady = ready;
}
-
diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h
index 1a3e307663..2fac5f53a6 100644
--- a/indra/llcharacter/llcharacter.h
+++ b/indra/llcharacter/llcharacter.h
@@ -177,7 +177,7 @@ public:
virtual LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset) { return LLVector3::zero; }
- virtual LLJoint* findCollisionVolume(U32 volume_id) { return NULL; }
+ virtual LLJoint* findCollisionVolume(S32 volume_id) { return NULL; }
virtual S32 getCollisionVolumeID(std::string &name) { return -1; }
diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index 330d812985..5d323ed5d6 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -1772,6 +1772,13 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
bin_data[BIN_DATA_LENGTH] = 0; // Ensure null termination
str = (char*)bin_data;
constraintp->mSourceConstraintVolume = mCharacter->getCollisionVolumeID(str);
+ if (constraintp->mSourceConstraintVolume == -1)
+ {
+ LL_WARNS() << "not a valid source constraint volume " << str
+ << " for animation " << asset_id << LL_ENDL;
+ delete constraintp;
+ return FALSE;
+ }
if (!dp.unpackVector3(constraintp->mSourceConstraintOffset, "source_offset"))
{
@@ -1808,6 +1815,13 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
{
constraintp->mConstraintTargetType = CONSTRAINT_TARGET_TYPE_BODY;
constraintp->mTargetConstraintVolume = mCharacter->getCollisionVolumeID(str);
+ if (constraintp->mTargetConstraintVolume == -1)
+ {
+ LL_WARNS() << "not a valid target constraint volume " << str
+ << " for animation " << asset_id << LL_ENDL;
+ delete constraintp;
+ return FALSE;
+ }
}
if (!dp.unpackVector3(constraintp->mTargetConstraintOffset, "target_offset"))
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index d9eb13d65a..af41b9e460 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -35,6 +35,7 @@ set(llcommon_SOURCE_FILES
llapp.cpp
llapr.cpp
llassettype.cpp
+ llatomic.cpp
llbase32.cpp
llbase64.cpp
llbitpack.cpp
@@ -135,6 +136,7 @@ set(llcommon_HEADER_FILES
llapp.h
llapr.h
llassettype.h
+ llatomic.h
llbase32.h
llbase64.h
llbitpack.h
@@ -255,6 +257,11 @@ set(llcommon_HEADER_FILES
set_source_files_properties(${llcommon_HEADER_FILES}
PROPERTIES HEADER_FILE_ONLY TRUE)
+if (BUGSPLAT_DB)
+ set_source_files_properties(llapp.cpp
+ PROPERTIES COMPILE_DEFINITIONS "LL_BUGSPLAT")
+endif (BUGSPLAT_DB)
+
list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
if(LLCOMMON_LINK_SHARED)
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 6cc9e804d4..421af3006e 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -392,7 +392,7 @@ void LLApp::setupErrorHandling(bool second_instance)
#if LL_WINDOWS
-#if LL_SEND_CRASH_REPORTS
+#if LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT)
EnableCrashingOnCrashes();
// This sets a callback to handle w32 signals to the console window.
@@ -454,8 +454,15 @@ void LLApp::setupErrorHandling(bool second_instance)
mExceptionHandler->set_handle_debug_exceptions(true);
}
}
-#endif
-#else
+#endif // LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT)
+#else // ! LL_WINDOWS
+
+#if defined(LL_BUGSPLAT)
+ // Don't install our own signal handlers -- BugSplat needs to hook them,
+ // or it's completely ineffectual.
+ bool installHandler = false;
+
+#else // ! LL_BUGSPLAT
//
// Start up signal handling.
//
@@ -463,9 +470,11 @@ void LLApp::setupErrorHandling(bool second_instance)
// thread, asynchronous signals can be delivered to any thread (in theory)
//
setup_signals();
-
+
// Add google breakpad exception handler configured for Darwin/Linux.
bool installHandler = true;
+#endif // ! LL_BUGSPLAT
+
#if LL_DARWIN
// For the special case of Darwin, we do not want to install the handler if
// the process is being debugged as the app will exit with value ABRT (6) if
@@ -498,7 +507,7 @@ void LLApp::setupErrorHandling(bool second_instance)
// installing the handler.
installHandler = true;
}
- #endif
+ #endif // ! LL_RELEASE_FOR_DOWNLOAD
if(installHandler && (mExceptionHandler == 0))
{
@@ -514,9 +523,9 @@ void LLApp::setupErrorHandling(bool second_instance)
google_breakpad::MinidumpDescriptor desc(mDumpPath);
mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1);
}
-#endif
+#endif // LL_LINUX
-#endif
+#endif // ! LL_WINDOWS
startErrorThread();
}
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index acd829d864..245c73e3a2 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -30,9 +30,8 @@
#include <map>
#include "llrun.h"
#include "llsd.h"
+#include <atomic>
// Forward declarations
-template <typename Type> class LLAtomic32;
-typedef LLAtomic32<U32> LLAtomicU32;
class LLErrorThread;
class LLLiveFile;
#if LL_LINUX
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index d353d06de2..29f0c7da9a 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -28,13 +28,12 @@
#include "linden_common.h"
#include "llapr.h"
+#include "llmutex.h"
#include "apr_dso.h"
#include "llthreadlocalstorage.h"
apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
-apr_thread_mutex_t *gLogMutexp = NULL;
-apr_thread_mutex_t *gCallStacksLogMutexp = NULL;
const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool
@@ -48,10 +47,6 @@ void ll_init_apr()
if (!gAPRPoolp)
{
apr_pool_create(&gAPRPoolp, NULL);
-
- // Initialize the logging mutex
- apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
- apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
}
if(!LLAPRFile::sAPRFilePoolp)
@@ -75,23 +70,6 @@ void ll_cleanup_apr()
LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
- if (gLogMutexp)
- {
- // Clean up the logging mutex
-
- // All other threads NEED to be done before we clean up APR, so this is okay.
- apr_thread_mutex_destroy(gLogMutexp);
- gLogMutexp = NULL;
- }
- if (gCallStacksLogMutexp)
- {
- // Clean up the logging mutex
-
- // All other threads NEED to be done before we clean up APR, so this is okay.
- apr_thread_mutex_destroy(gCallStacksLogMutexp);
- gCallStacksLogMutexp = NULL;
- }
-
LLThreadLocalPointerBase::destroyAllThreadLocalStorage();
if (gAPRPoolp)
@@ -168,26 +146,19 @@ apr_pool_t* LLAPRPool::getAPRPool()
LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
: LLAPRPool(parent, size, releasePoolFlag),
mNumActiveRef(0),
- mNumTotalRef(0),
- mMutexPool(NULL),
- mMutexp(NULL)
+ mNumTotalRef(0)
{
//create mutex
if(!is_local) //not a local apr_pool, that is: shared by multiple threads.
{
- apr_pool_create(&mMutexPool, NULL); // Create a pool for mutex
- apr_thread_mutex_create(&mMutexp, APR_THREAD_MUTEX_UNNESTED, mMutexPool);
+ mMutexp.reset(new std::mutex());
}
}
LLVolatileAPRPool::~LLVolatileAPRPool()
{
//delete mutex
- if(mMutexp)
- {
- apr_thread_mutex_destroy(mMutexp);
- apr_pool_destroy(mMutexPool);
- }
+ mMutexp.reset();
}
//
@@ -201,7 +172,7 @@ apr_pool_t* LLVolatileAPRPool::getAPRPool()
apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool()
{
- LLScopedLock lock(mMutexp) ;
+ LLScopedLock lock(mMutexp.get()) ;
mNumTotalRef++ ;
mNumActiveRef++ ;
@@ -216,7 +187,7 @@ apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool()
void LLVolatileAPRPool::clearVolatileAPRPool()
{
- LLScopedLock lock(mMutexp) ;
+ LLScopedLock lock(mMutexp.get());
if(mNumActiveRef > 0)
{
@@ -250,44 +221,6 @@ BOOL LLVolatileAPRPool::isFull()
{
return mNumTotalRef > FULL_VOLATILE_APR_POOL ;
}
-//---------------------------------------------------------------------
-//
-// LLScopedLock
-//
-LLScopedLock::LLScopedLock(apr_thread_mutex_t* mutex) : mMutex(mutex)
-{
- if(mutex)
- {
- if(ll_apr_warn_status(apr_thread_mutex_lock(mMutex)))
- {
- mLocked = false;
- }
- else
- {
- mLocked = true;
- }
- }
- else
- {
- mLocked = false;
- }
-}
-
-LLScopedLock::~LLScopedLock()
-{
- unlock();
-}
-
-void LLScopedLock::unlock()
-{
- if(mLocked)
- {
- if(!ll_apr_warn_status(apr_thread_mutex_unlock(mMutex)))
- {
- mLocked = false;
- }
- }
-}
//---------------------------------------------------------------------
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 1ac5c4e9b2..da50dda103 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -36,15 +36,22 @@
#include <boost/noncopyable.hpp>
#include "llwin32headerslean.h"
#include "apr_thread_proc.h"
-#include "apr_thread_mutex.h"
#include "apr_getopt.h"
#include "apr_signal.h"
-#include "apr_atomic.h"
#include "llstring.h"
-extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
-extern apr_thread_mutex_t* gCallStacksLogMutexp;
+#if LL_WINDOWS
+#pragma warning (push)
+#pragma warning (disable:4265)
+#endif
+// warning C4265: 'std::_Pad' : class has virtual functions, but destructor is not virtual
+
+#include <mutex>
+
+#if LL_WINDOWS
+#pragma warning (pop)
+#endif
struct apr_dso_handle_t;
/**
@@ -120,77 +127,9 @@ private:
S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating.
- apr_thread_mutex_t *mMutexp;
- apr_pool_t *mMutexPool;
+ std::unique_ptr<std::mutex> mMutexp;
} ;
-/**
- * @class LLScopedLock
- * @brief Small class to help lock and unlock mutexes.
- *
- * This class is used to have a stack level lock once you already have
- * an apr mutex handy. The constructor handles the lock, and the
- * destructor handles the unlock. Instances of this class are
- * <b>not</b> thread safe.
- */
-class LL_COMMON_API LLScopedLock : private boost::noncopyable
-{
-public:
- /**
- * @brief Constructor which accepts a mutex, and locks it.
- *
- * @param mutex An allocated APR mutex. If you pass in NULL,
- * this wrapper will not lock.
- */
- LLScopedLock(apr_thread_mutex_t* mutex);
-
- /**
- * @brief Destructor which unlocks the mutex if still locked.
- */
- ~LLScopedLock();
-
- /**
- * @brief Check lock.
- */
- bool isLocked() const { return mLocked; }
-
- /**
- * @brief This method unlocks the mutex.
- */
- void unlock();
-
-protected:
- bool mLocked;
- apr_thread_mutex_t* mMutex;
-};
-
-template <typename Type> class LLAtomic32
-{
-public:
- LLAtomic32<Type>() {};
- LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
- ~LLAtomic32<Type>() {};
-
- operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
-
- Type CurrentValue() const { apr_uint32_t data = apr_atomic_read32(const_cast< volatile apr_uint32_t* >(&mData)); return Type(data); }
-
- Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
- void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
- void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
- Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
- Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
-
- Type operator ++() { return apr_atomic_inc32(&mData); } // Type++
- Type operator --() { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
-
-private:
- volatile apr_uint32_t mData;
-};
-
-typedef LLAtomic32<U32> LLAtomicU32;
-typedef LLAtomic32<S32> LLAtomicS32;
-
// File IO convenience functions.
// Returns NULL if the file fails to open, sets *sizep to file size if not NULL
// abbreviated flags
diff --git a/indra/llcommon/llatomic.cpp b/indra/llcommon/llatomic.cpp
new file mode 100644
index 0000000000..93aba1f460
--- /dev/null
+++ b/indra/llcommon/llatomic.cpp
@@ -0,0 +1,28 @@
+/**
+ * @file llatomic.cpp
+ *
+ * $LicenseInfo:firstyear=2018&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2018, 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 "llatomic.h"
+
+//============================================================================
diff --git a/indra/llcommon/llatomic.h b/indra/llcommon/llatomic.h
new file mode 100644
index 0000000000..8de773846c
--- /dev/null
+++ b/indra/llcommon/llatomic.h
@@ -0,0 +1,69 @@
+/**
+ * @file llatomic.h
+ * @brief Base classes for atomic.
+ *
+ * $LicenseInfo:firstyear=2018&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2018, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLATOMIC_H
+#define LL_LLATOMIC_H
+
+#include "stdtypes.h"
+
+#include <atomic>
+
+template <typename Type, typename AtomicType = std::atomic< Type > > class LLAtomicBase
+{
+public:
+ LLAtomicBase() {};
+ LLAtomicBase(Type x) { mData.store(x); }
+ ~LLAtomicBase() {};
+
+ operator const Type() { return mData; }
+
+ Type CurrentValue() const { return mData; }
+
+ Type operator =(const Type& x) { mData.store(x); return mData; }
+ void operator -=(Type x) { mData -= x; }
+ void operator +=(Type x) { mData += x; }
+ Type operator ++(int) { return mData++; }
+ Type operator --(int) { return mData--; }
+
+ Type operator ++() { return ++mData; }
+ Type operator --() { return --mData; }
+
+private:
+ AtomicType mData;
+};
+
+// Typedefs for specialized versions. Using std::atomic_(u)int32_t to get the optimzed implementation.
+#ifdef LL_WINDOWS
+typedef LLAtomicBase<U32, std::atomic_uint32_t> LLAtomicU32;
+typedef LLAtomicBase<S32, std::atomic_int32_t> LLAtomicS32;
+#else
+typedef LLAtomicBase<U32, std::atomic_uint> LLAtomicU32;
+typedef LLAtomicBase<S32, std::atomic_int> LLAtomicS32;
+#endif
+
+typedef LLAtomicBase<bool, std::atomic_bool> LLAtomicBool;
+
+#endif // LL_LLATOMIC_H
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
index 8fb27af6a4..c551413811 100644
--- a/indra/llcommon/llcoros.h
+++ b/indra/llcommon/llcoros.h
@@ -170,6 +170,26 @@ public:
static bool get_consuming();
/**
+ * RAII control of the consuming flag
+ */
+ class OverrideConsuming
+ {
+ public:
+ OverrideConsuming(bool consuming):
+ mPrevConsuming(get_consuming())
+ {
+ set_consuming(consuming);
+ }
+ ~OverrideConsuming()
+ {
+ set_consuming(mPrevConsuming);
+ }
+
+ private:
+ bool mPrevConsuming;
+ };
+
+ /**
* Please do NOT directly use boost::dcoroutines::future! It is essential
* to maintain the "current" coroutine at every context switch. This
* Future wraps the essential boost::dcoroutines::future functionality
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 40eb7d9bac..335a0995fe 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -132,8 +132,6 @@ namespace {
mFile.sync_with_stdio(false);
}
}
- mWantsTime = true;
- mWantsTags = true;
}
~RecordToFile()
@@ -175,7 +173,7 @@ namespace {
public:
RecordToStderr(bool timestamp) : mUseANSI(ANSI_PROBE)
{
- mWantsTime = timestamp;
+ this->showMultiline(true);
}
virtual bool enabled() override
@@ -241,7 +239,13 @@ namespace {
class RecordToFixedBuffer : public LLError::Recorder
{
public:
- RecordToFixedBuffer(LLLineBuffer* buffer) : mBuffer(buffer) { }
+ RecordToFixedBuffer(LLLineBuffer* buffer)
+ : mBuffer(buffer)
+ {
+ this->showMultiline(true);
+ this->showTags(false);
+ this->showLocation(false);
+ }
virtual bool enabled() override
{
@@ -263,7 +267,11 @@ namespace {
{
public:
RecordToWinDebug()
- {}
+ {
+ this->showMultiline(true);
+ this->showTags(false);
+ this->showLocation(false);
+ }
virtual bool enabled() override
{
@@ -382,15 +390,22 @@ namespace
{
llifstream file(filename().c_str());
- if (file.is_open())
+ if (!file.is_open())
{
- LLSDSerialize::fromXML(configuration, file);
+ LL_WARNS() << filename() << " failed to open file; not changing configuration" << LL_ENDL;
+ return false;
+ }
+
+ if (LLSDSerialize::fromXML(configuration, file) == LLSDParser::PARSE_FAILURE)
+ {
+ LL_WARNS() << filename() << " parcing error; not changing configuration" << LL_ENDL;
+ return false;
}
- if (configuration.isUndefined())
+ if (configuration.isUndefined() || !configuration.isMap() || configuration.emptyMap())
{
- LL_WARNS() << filename() << " missing, ill-formed,"
- " or simply undefined; not changing configuration"
+ LL_WARNS() << filename() << " missing, ill-formed, or simply undefined"
+ " content; not changing configuration"
<< LL_ENDL;
return false;
}
@@ -412,6 +427,7 @@ namespace
public:
std::ostringstream messageStream;
bool messageStreamInUse;
+ std::string mFatalMessage;
void addCallSite(LLError::CallSite&);
void invalidateCallSites();
@@ -454,8 +470,6 @@ namespace LLError
public:
virtual ~SettingsConfig();
- bool mPrintLocation;
-
LLError::ELevel mDefaultLevel;
bool mLogAlwaysFlush;
@@ -500,7 +514,6 @@ namespace LLError
SettingsConfig::SettingsConfig()
: LLRefCount(),
- mPrintLocation(false),
mDefaultLevel(LLError::LEVEL_DEBUG),
mLogAlwaysFlush(true),
mEnabledLogTypesMask(255),
@@ -706,23 +719,22 @@ namespace LLError
commonInit(user_dir, app_dir, log_to_stderr);
}
- void setPrintLocation(bool print)
+ void setFatalFunction(const FatalFunction& f)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
- s->mPrintLocation = print;
+ s->mCrashFunction = f;
}
- void setFatalFunction(const FatalFunction& f)
+ FatalFunction getFatalFunction()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
- s->mCrashFunction = f;
+ return s->mCrashFunction;
}
- FatalFunction getFatalFunction()
- {
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
- return s->mCrashFunction;
- }
+ std::string getFatalMessage()
+ {
+ return Globals::getInstance()->mFatalMessage;
+ }
void setTimeFunction(TimeFunction f)
{
@@ -845,7 +857,6 @@ namespace LLError
s->mTagLevelMap.clear();
s->mUniqueLogMessages.clear();
- setPrintLocation(config["print-location"]);
setDefaultLevel(decodeLevel(config["default-level"]));
if (config.has("log-always-flush"))
{
@@ -856,19 +867,24 @@ namespace LLError
setEnabledLogTypesMask(config["enabled-log-types-mask"].asInteger());
}
- LLSD sets = config["settings"];
- LLSD::array_const_iterator a, end;
- for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a)
- {
- const LLSD& entry = *a;
-
- ELevel level = decodeLevel(entry["level"]);
-
- setLevels(s->mFunctionLevelMap, entry["functions"], level);
- setLevels(s->mClassLevelMap, entry["classes"], level);
- setLevels(s->mFileLevelMap, entry["files"], level);
- setLevels(s->mTagLevelMap, entry["tags"], level);
- }
+ if (config.has("settings") && config["settings"].isArray())
+ {
+ LLSD sets = config["settings"];
+ LLSD::array_const_iterator a, end;
+ for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a)
+ {
+ const LLSD& entry = *a;
+ if (entry.isMap() && !entry.emptyMap())
+ {
+ ELevel level = decodeLevel(entry["level"]);
+
+ setLevels(s->mFunctionLevelMap, entry["functions"], level);
+ setLevels(s->mClassLevelMap, entry["classes"], level);
+ setLevels(s->mFileLevelMap, entry["files"], level);
+ setLevels(s->mTagLevelMap, entry["tags"], level);
+ }
+ }
+ }
}
}
@@ -876,11 +892,12 @@ namespace LLError
namespace LLError
{
Recorder::Recorder()
- : mWantsTime(false),
- mWantsTags(false),
- mWantsLevel(true),
- mWantsLocation(false),
- mWantsFunctionName(true)
+ : mWantsTime(true)
+ , mWantsTags(true)
+ , mWantsLevel(true)
+ , mWantsLocation(true)
+ , mWantsFunctionName(true)
+ , mWantsMultiline(false)
{
}
@@ -917,6 +934,42 @@ namespace LLError
return mWantsFunctionName;
}
+ // virtual
+ bool Recorder::wantsMultiline()
+ {
+ return mWantsMultiline;
+ }
+
+ void Recorder::showTime(bool show)
+ {
+ mWantsTime = show;
+ }
+
+ void Recorder::showTags(bool show)
+ {
+ mWantsTags = show;
+ }
+
+ void Recorder::showLevel(bool show)
+ {
+ mWantsLevel = show;
+ }
+
+ void Recorder::showLocation(bool show)
+ {
+ mWantsLocation = show;
+ }
+
+ void Recorder::showFunctionName(bool show)
+ {
+ mWantsFunctionName = show;
+ }
+
+ void Recorder::showMultiline(bool show)
+ {
+ mWantsMultiline = show;
+ }
+
void addRecorder(RecorderPtr recorder)
{
if (!recorder)
@@ -949,17 +1002,15 @@ namespace LLError
s->mFileRecorder.reset();
s->mFileRecorderFileName.clear();
- if (file_name.empty())
+ if (!file_name.empty())
{
- return;
- }
-
- RecorderPtr recordToFile(new RecordToFile(file_name));
- if (boost::dynamic_pointer_cast<RecordToFile>(recordToFile)->okay())
- {
- s->mFileRecorderFileName = file_name;
- s->mFileRecorder = recordToFile;
- addRecorder(recordToFile);
+ RecorderPtr recordToFile(new RecordToFile(file_name));
+ if (boost::dynamic_pointer_cast<RecordToFile>(recordToFile)->okay())
+ {
+ s->mFileRecorderFileName = file_name;
+ s->mFileRecorder = recordToFile;
+ addRecorder(recordToFile);
+ }
}
}
@@ -970,14 +1021,12 @@ namespace LLError
removeRecorder(s->mFixedBufferRecorder);
s->mFixedBufferRecorder.reset();
- if (!fixedBuffer)
+ if (fixedBuffer)
{
- return;
- }
-
- RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer));
- s->mFixedBufferRecorder = recordToFixedBuffer;
- addRecorder(recordToFixedBuffer);
+ RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer));
+ s->mFixedBufferRecorder = recordToFixedBuffer;
+ addRecorder(recordToFixedBuffer);
+ }
}
std::string logFileName()
@@ -989,8 +1038,9 @@ namespace LLError
namespace
{
- void addEscapedMessage(std::ostream& out, const std::string& message)
+ std::string escapedMessageLines(const std::string& message)
{
+ std::ostringstream out;
size_t written_out = 0;
size_t all_content = message.length();
size_t escape_char_index; // always relative to start of message
@@ -1026,13 +1076,16 @@ namespace
// write whatever was left
out << message.substr(written_out, std::string::npos);
}
+ return out.str();
}
- void writeToRecorders(const LLError::CallSite& site, const std::string& escaped_message)
+ void writeToRecorders(const LLError::CallSite& site, const std::string& message)
{
LLError::ELevel level = site.mLevel;
LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
-
+
+ std::string escaped_message;
+
for (Recorders::const_iterator i = s->mRecorders.begin();
i != s->mRecorders.end();
++i)
@@ -1064,7 +1117,7 @@ namespace
}
message_stream << " ";
- if (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation)
+ if (r->wantsLocation() || level == LLError::LEVEL_ERROR)
{
message_stream << site.mLocationString;
}
@@ -1076,7 +1129,18 @@ namespace
}
message_stream << " : ";
- message_stream << escaped_message;
+ if (r->wantsMultiline())
+ {
+ message_stream << message;
+ }
+ else
+ {
+ if (escaped_message.empty())
+ {
+ escaped_message = escapedMessageLines(message);
+ }
+ message_stream << escaped_message;
+ }
r->recordMessage(level, message_stream.str());
}
@@ -1084,6 +1148,9 @@ namespace
}
namespace {
+ LLMutex gLogMutex;
+ LLMutex gCallStacksLogMutex;
+
bool checkLevelMap(const LevelMap& map, const std::string& key,
LLError::ELevel& level)
{
@@ -1123,56 +1190,6 @@ namespace {
}
return found_level;
}
-
- class LogLock
- {
- public:
- LogLock();
- ~LogLock();
- bool ok() const { return mOK; }
- private:
- bool mLocked;
- bool mOK;
- };
-
- LogLock::LogLock()
- : mLocked(false), mOK(false)
- {
- if (!gLogMutexp)
- {
- mOK = true;
- return;
- }
-
- const int MAX_RETRIES = 5;
- for (int attempts = 0; attempts < MAX_RETRIES; ++attempts)
- {
- apr_status_t s = apr_thread_mutex_trylock(gLogMutexp);
- if (!APR_STATUS_IS_EBUSY(s))
- {
- mLocked = true;
- mOK = true;
- return;
- }
-
- ms_sleep(1);
- //apr_thread_yield();
- // Just yielding won't necessarily work, I had problems with
- // this on Linux - doug 12/02/04
- }
-
- // We're hosed, we can't get the mutex. Blah.
- std::cerr << "LogLock::LogLock: failed to get mutex for log"
- << std::endl;
- }
-
- LogLock::~LogLock()
- {
- if (mLocked)
- {
- apr_thread_mutex_unlock(gLogMutexp);
- }
- }
}
namespace LLError
@@ -1180,8 +1197,8 @@ namespace LLError
bool Log::shouldLog(CallSite& site)
{
- LogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gLogMutex, 5);
+ if (!lock.isLocked())
{
return false;
}
@@ -1231,11 +1248,11 @@ namespace LLError
std::ostringstream* Log::out()
{
- LogLock lock;
+ LLMutexTrylock lock(&gLogMutex,5);
// If we hit a logging request very late during shutdown processing,
// when either of the relevant LLSingletons has already been deleted,
// DO NOT resurrect them.
- if (lock.ok() && ! (Settings::wasDeleted() || Globals::wasDeleted()))
+ if (lock.isLocked() && ! (Settings::wasDeleted() || Globals::wasDeleted()))
{
Globals* g = Globals::getInstance();
@@ -1251,8 +1268,8 @@ namespace LLError
void Log::flush(std::ostringstream* out, char* message)
{
- LogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gLogMutex,5);
+ if (!lock.isLocked())
{
return;
}
@@ -1291,8 +1308,8 @@ namespace LLError
void Log::flush(std::ostringstream* out, const CallSite& site)
{
- LogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gLogMutex,5);
+ if (!lock.isLocked())
{
return;
}
@@ -1320,10 +1337,11 @@ namespace LLError
delete out;
}
- std::ostringstream message_stream;
if (site.mPrintOnce)
{
+ std::ostringstream message_stream;
+
std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message);
if (messageIter != s->mUniqueLogMessages.end())
{
@@ -1343,15 +1361,19 @@ namespace LLError
message_stream << "ONCE: ";
s->mUniqueLogMessages[message] = 1;
}
+ message_stream << message;
+ message = message_stream.str();
}
- addEscapedMessage(message_stream, message);
+ writeToRecorders(site, message);
- writeToRecorders(site, message_stream.str());
-
- if (site.mLevel == LEVEL_ERROR && s->mCrashFunction)
+ if (site.mLevel == LEVEL_ERROR)
{
- s->mCrashFunction(message_stream.str());
+ g->mFatalMessage = message;
+ if (s->mCrashFunction)
+ {
+ s->mCrashFunction(message);
+ }
}
}
}
@@ -1457,69 +1479,6 @@ namespace LLError
char** LLCallStacks::sBuffer = NULL ;
S32 LLCallStacks::sIndex = 0 ;
-#define SINGLE_THREADED 1
-
- class CallStacksLogLock
- {
- public:
- CallStacksLogLock();
- ~CallStacksLogLock();
-
-#if SINGLE_THREADED
- bool ok() const { return true; }
-#else
- bool ok() const { return mOK; }
- private:
- bool mLocked;
- bool mOK;
-#endif
- };
-
-#if SINGLE_THREADED
- CallStacksLogLock::CallStacksLogLock()
- {
- }
- CallStacksLogLock::~CallStacksLogLock()
- {
- }
-#else
- CallStacksLogLock::CallStacksLogLock()
- : mLocked(false), mOK(false)
- {
- if (!gCallStacksLogMutexp)
- {
- mOK = true;
- return;
- }
-
- const int MAX_RETRIES = 5;
- for (int attempts = 0; attempts < MAX_RETRIES; ++attempts)
- {
- apr_status_t s = apr_thread_mutex_trylock(gCallStacksLogMutexp);
- if (!APR_STATUS_IS_EBUSY(s))
- {
- mLocked = true;
- mOK = true;
- return;
- }
-
- ms_sleep(1);
- }
-
- // We're hosed, we can't get the mutex. Blah.
- std::cerr << "CallStacksLogLock::CallStacksLogLock: failed to get mutex for log"
- << std::endl;
- }
-
- CallStacksLogLock::~CallStacksLogLock()
- {
- if (mLocked)
- {
- apr_thread_mutex_unlock(gCallStacksLogMutexp);
- }
- }
-#endif
-
//static
void LLCallStacks::allocateStackBuffer()
{
@@ -1548,8 +1507,8 @@ namespace LLError
//static
void LLCallStacks::push(const char* function, const int line)
{
- CallStacksLogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+ if (!lock.isLocked())
{
return;
}
@@ -1583,8 +1542,8 @@ namespace LLError
//static
void LLCallStacks::end(std::ostringstream* _out)
{
- CallStacksLogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+ if (!lock.isLocked())
{
return;
}
@@ -1605,8 +1564,8 @@ namespace LLError
//static
void LLCallStacks::print()
{
- CallStacksLogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+ if (!lock.isLocked())
{
return;
}
@@ -1643,8 +1602,8 @@ namespace LLError
bool debugLoggingEnabled(const std::string& tag)
{
- LogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gLogMutex, 5);
+ if (!lock.isLocked())
{
return false;
}
@@ -1656,3 +1615,4 @@ bool debugLoggingEnabled(const std::string& tag)
}
+
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index 1730f0c640..276d22fc36 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -106,6 +106,9 @@ namespace LLError
LL_COMMON_API FatalFunction getFatalFunction();
// Retrieve the previously-set FatalFunction
+ LL_COMMON_API std::string getFatalMessage();
+ // Retrieve the message last passed to FatalFunction, if any
+
/// temporarily override the FatalFunction for the duration of a
/// particular scope, e.g. for unit tests
class LL_COMMON_API OverrideFatalFunction
@@ -151,13 +154,22 @@ namespace LLError
bool wantsLevel();
bool wantsLocation();
bool wantsFunctionName();
+ bool wantsMultiline();
+
+ void showTime(bool show);
+ void showTags(bool show);
+ void showLevel(bool show);
+ void showLocation(bool show);
+ void showFunctionName(bool show);
+ void showMultiline(bool show);
protected:
- bool mWantsTime,
- mWantsTags,
- mWantsLevel,
- mWantsLocation,
- mWantsFunctionName;
+ bool mWantsTime;
+ bool mWantsTags;
+ bool mWantsLevel;
+ bool mWantsLocation;
+ bool mWantsFunctionName;
+ bool mWantsMultiline;
};
typedef boost::shared_ptr<Recorder> RecorderPtr;
diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp
index dce97b5411..eedd8c92b5 100644
--- a/indra/llcommon/llevents.cpp
+++ b/indra/llcommon/llevents.cpp
@@ -545,10 +545,8 @@ bool LLEventStream::post(const LLSD& event)
*****************************************************************************/
bool LLEventMailDrop::post(const LLSD& event)
{
- bool posted = false;
-
- if (!mSignal->empty())
- posted = LLEventStream::post(event);
+ // forward the call to our base class
+ bool posted = LLEventStream::post(event);
if (!posted)
{ // if the event was not handled we will save it for later so that it can
@@ -564,16 +562,25 @@ LLBoundListener LLEventMailDrop::listen_impl(const std::string& name,
const NameList& after,
const NameList& before)
{
- if (!mEventHistory.empty())
+ // Before actually connecting this listener for subsequent post() calls,
+ // first feed each of the saved events, in order, to the new listener.
+ // Remove any that this listener consumes -- Effective STL, Item 9.
+ for (auto hi(mEventHistory.begin()), hend(mEventHistory.end()); hi != hend; )
{
- if (listener(mEventHistory.front()))
+ if (listener(*hi))
{
- mEventHistory.pop_front();
+ // new listener consumed this event, erase it
+ hi = mEventHistory.erase(hi);
+ }
+ else
+ {
+ // listener did not consume this event, just move along
+ ++hi;
}
}
+ // let base class perform the actual connection
return LLEventStream::listen_impl(name, listener, after, before);
-
}
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h
index 1d51c660ed..5d60c63810 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -650,15 +650,21 @@ public:
* LLEventMailDrop
*****************************************************************************/
/**
- * LLEventMailDrop is a specialization of LLEventStream. Events are posted normally,
- * however if no listeners return that they have handled the event it is placed in
- * a queue. Subsequent attaching listeners will receive stored events from the queue
- * until a listener indicates that the event has been handled. In order to receive
- * multiple events from a mail drop the listener must disconnect and reconnect.
+ * LLEventMailDrop is a specialization of LLEventStream. Events are posted
+ * normally, however if no listener returns that it has handled the event
+ * (returns true), it is placed in a queue. Subsequent attaching listeners
+ * will receive stored events from the queue until some listener indicates
+ * that the event has been handled.
+ *
+ * LLEventMailDrop completely decouples the timing of post() calls from
+ * listen() calls: every event posted to an LLEventMailDrop is eventually seen
+ * by all listeners, until some listener consumes it. The caveat is that each
+ * event *must* eventually reach a listener that will consume it, else the
+ * queue will grow to arbitrary length.
*
* @NOTE: When using an LLEventMailDrop (or LLEventQueue) with a LLEventTimeout or
- * LLEventFilter attaching the filter downstream using Timeout's constructor will
- * cause the MailDrop to discharge any of it's stored events. The timeout should
+ * LLEventFilter attaching the filter downstream, using Timeout's constructor will
+ * cause the MailDrop to discharge any of its stored events. The timeout should
* instead be connected upstream using its listen() method.
* See llcoro::suspendUntilEventOnWithTimeout() for an example.
*/
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index fc203f78e1..8355b1e797 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -30,6 +30,7 @@
#if LL_WINDOWS
#include "llwin32headerslean.h"
#include <stdlib.h> // Windows errno
+#include <vector>
#else
#include <errno.h>
#endif
@@ -134,8 +135,10 @@ int warnif(const std::string& desc, const std::string& filename, int rc, int acc
{
// Only do any of this stuff (before LL_ENDL) if it will be logged.
LL_DEBUGS("LLFile") << empty;
- const char* TEMP = getenv("TEMP");
- if (! TEMP)
+ // would be nice to use LLDir for this, but dependency goes the
+ // wrong way
+ const char* TEMP = LLFile::tmpdir();
+ if (! (TEMP && *TEMP))
{
LL_CONT << "No $TEMP, not running 'handle'";
}
@@ -341,17 +344,13 @@ const char *LLFile::tmpdir()
#if LL_WINDOWS
sep = '\\';
- DWORD len = GetTempPathW(0, L"");
- llutf16string utf16path;
- utf16path.resize(len + 1);
- len = GetTempPathW(static_cast<DWORD>(utf16path.size()), &utf16path[0]);
- utf8path = utf16str_to_utf8str(utf16path);
+ std::vector<wchar_t> utf16path(MAX_PATH + 1);
+ GetTempPathW(utf16path.size(), &utf16path[0]);
+ utf8path = ll_convert_wide_to_string(&utf16path[0]);
#else
sep = '/';
- char *env = getenv("TMPDIR");
-
- utf8path = env ? env : "/tmp/";
+ utf8path = LLStringUtil::getenv("TMPDIR", "/tmp/");
#endif
if (utf8path[utf8path.size() - 1] != sep)
{
diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp
index d394f179fb..bd4db8be84 100644
--- a/indra/llcommon/llfixedbuffer.cpp
+++ b/indra/llcommon/llfixedbuffer.cpp
@@ -31,7 +31,7 @@
LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
: LLLineBuffer(),
mMaxLines(max_lines),
- mMutex(NULL)
+ mMutex()
{
mTimer.reset();
}
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index f1f4226c40..7f5b9b4ac2 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -2115,6 +2115,9 @@ namespace LLInitParam
typedef typename super_t::iterator iterator;
typedef typename super_t::const_iterator const_iterator;
+ using super_t::operator();
+ using super_t::operator const container_t&;
+
explicit Multiple(const char* name = "")
: super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount)
{}
diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp
index 11fc53f8c8..3f990f4869 100644
--- a/indra/llcommon/llinstancetracker.cpp
+++ b/indra/llcommon/llinstancetracker.cpp
@@ -36,17 +36,16 @@
void LLInstanceTrackerBase::StaticBase::incrementDepth()
{
- apr_atomic_inc32(&sIterationNestDepth);
+ ++sIterationNestDepth;
}
void LLInstanceTrackerBase::StaticBase::decrementDepth()
{
llassert(sIterationNestDepth);
- apr_atomic_dec32(&sIterationNestDepth);
+ --sIterationNestDepth;
}
U32 LLInstanceTrackerBase::StaticBase::getDepth()
{
- apr_uint32_t data = apr_atomic_read32(&sIterationNestDepth);
- return data;
+ return sIterationNestDepth;
}
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 910c8dbd99..363d0bcbd5 100644
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -28,6 +28,7 @@
#ifndef LL_LLINSTANCETRACKER_H
#define LL_LLINSTANCETRACKER_H
+#include <atomic>
#include <map>
#include <typeinfo>
@@ -81,8 +82,12 @@ protected:
void decrementDepth();
U32 getDepth();
private:
- U32 sIterationNestDepth;
- };
+#ifdef LL_WINDOWS
+ std::atomic_uint32_t sIterationNestDepth;
+#else
+ std::atomic_uint sIterationNestDepth;
+#endif
+ };
};
LL_COMMON_API void assert_main_thread();
diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index c87d2a3e58..cf8f8cc6a5 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -47,9 +47,9 @@ class LLLeapImpl: public LLLeap
LOG_CLASS(LLLeap);
public:
// Called only by LLLeap::create()
- LLLeapImpl(const std::string& desc, const std::vector<std::string>& plugin):
+ LLLeapImpl(const LLProcess::Params& cparams):
// We might reassign mDesc in the constructor body if it's empty here.
- mDesc(desc),
+ mDesc(cparams.desc),
// We expect multiple LLLeapImpl instances. Definitely tweak
// mDonePump's name for uniqueness.
mDonePump("LLLeap", true),
@@ -67,17 +67,17 @@ public:
// this class or method name.
mListener(new LLLeapListener(boost::bind(&LLLeapImpl::connect, this, _1, _2)))
{
- // Rule out empty vector
- if (plugin.empty())
+ // Rule out unpopulated Params block
+ if (! cparams.executable.isProvided())
{
LLTHROW(Error("no plugin command"));
}
// Don't leave desc empty either, but in this case, if we weren't
// given one, we'll fake one.
- if (desc.empty())
+ if (mDesc.empty())
{
- mDesc = LLProcess::basename(plugin[0]);
+ mDesc = LLProcess::basename(cparams.executable);
// how about a toLower() variant that returns the transformed string?!
std::string desclower(mDesc);
LLStringUtil::toLower(desclower);
@@ -87,9 +87,9 @@ public:
// notice Python specially: we provide Python LLSD serialization
// support, so there's a pretty good reason to implement plugins
// in that language.
- if (plugin.size() >= 2 && (desclower == "python" || desclower == "python.exe"))
+ if (cparams.args.size() && (desclower == "python" || desclower == "python.exe"))
{
- mDesc = LLProcess::basename(plugin[1]);
+ mDesc = LLProcess::basename(cparams.args()[0]);
}
}
@@ -97,14 +97,10 @@ public:
mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::bad_launch, this, _1));
// Okay, launch child.
- LLProcess::Params params;
+ // Get a modifiable copy of params block to set files and postend.
+ LLProcess::Params params(cparams);
+ // copy our deduced mDesc back into the params block
params.desc = mDesc;
- std::vector<std::string>::const_iterator pi(plugin.begin()), pend(plugin.end());
- params.executable = *pi++;
- for ( ; pi != pend; ++pi)
- {
- params.args.add(*pi);
- }
params.files.add(LLProcess::FileParam("pipe")); // stdin
params.files.add(LLProcess::FileParam("pipe")); // stdout
params.files.add(LLProcess::FileParam("pipe")); // stderr
@@ -429,17 +425,17 @@ private:
boost::scoped_ptr<LLLeapListener> mListener;
};
-// This must follow the declaration of LLLeapImpl, so it may as well be last.
-LLLeap* LLLeap::create(const std::string& desc, const std::vector<std::string>& plugin, bool exc)
+// These must follow the declaration of LLLeapImpl, so they may as well be last.
+LLLeap* LLLeap::create(const LLProcess::Params& params, bool exc)
{
// If caller is willing to permit exceptions, just instantiate.
if (exc)
- return new LLLeapImpl(desc, plugin);
+ return new LLLeapImpl(params);
// Caller insists on suppressing LLLeap::Error. Very well, catch it.
try
{
- return new LLLeapImpl(desc, plugin);
+ return new LLLeapImpl(params);
}
catch (const LLLeap::Error&)
{
@@ -447,6 +443,23 @@ LLLeap* LLLeap::create(const std::string& desc, const std::vector<std::string>&
}
}
+LLLeap* LLLeap::create(const std::string& desc, const std::vector<std::string>& plugin, bool exc)
+{
+ LLProcess::Params params;
+ params.desc = desc;
+ std::vector<std::string>::const_iterator pi(plugin.begin()), pend(plugin.end());
+ // could validate here, but let's rely on LLLeapImpl's constructor
+ if (pi != pend)
+ {
+ params.executable = *pi++;
+ }
+ for ( ; pi != pend; ++pi)
+ {
+ params.args.add(*pi);
+ }
+ return create(params, exc);
+}
+
LLLeap* LLLeap::create(const std::string& desc, const std::string& plugin, bool exc)
{
// Use LLStringUtil::getTokens() to parse the command line
diff --git a/indra/llcommon/llleap.h b/indra/llcommon/llleap.h
index 8aac8a64c5..7cecdf2f8f 100644
--- a/indra/llcommon/llleap.h
+++ b/indra/llcommon/llleap.h
@@ -14,6 +14,7 @@
#include "llinstancetracker.h"
#include "llexception.h"
+#include "llprocess.h"
#include <string>
#include <vector>
@@ -62,6 +63,19 @@ public:
bool exc=true);
/**
+ * Pass an LLProcess::Params instance to specify desc, executable, args et al.
+ *
+ * Note that files and postend are set implicitly; any values you set in
+ * those fields will be disregarded.
+ *
+ * Pass exc=false to suppress LLLeap::Error exception. Obviously in that
+ * case the caller cannot discover the nature of the error, merely that an
+ * error of some kind occurred (because create() returned NULL). Either
+ * way, the error is logged.
+ */
+ static LLLeap* create(const LLProcess::Params& params, bool exc=true);
+
+ /**
* Exception thrown for invalid create() arguments, e.g. no plugin
* program. This is more resiliant than an LL_ERRS failure, because the
* string(s) passed to create() might come from an external source. This
diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp
index 9c13ef9e30..75f43a4704 100644
--- a/indra/llcommon/llmutex.cpp
+++ b/indra/llcommon/llmutex.cpp
@@ -24,47 +24,22 @@
*/
#include "linden_common.h"
-#include "llapr.h"
-
-#include "apr_portable.h"
#include "llmutex.h"
#include "llthread.h"
+#include "lltimer.h"
//============================================================================
-LLMutex::LLMutex(apr_pool_t *poolp) :
- mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD)
+LLMutex::LLMutex() :
+ mCount(0),
+ mLockingThread(NO_THREAD)
{
- //if (poolp)
- //{
- // mIsLocalPool = FALSE;
- // mAPRPoolp = poolp;
- //}
- //else
- {
- mIsLocalPool = TRUE;
- apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
- }
- apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
}
LLMutex::~LLMutex()
{
-#if MUTEX_DEBUG
- //bad assertion, the subclass LLSignal might be "locked", and that's OK
- //llassert_always(!isLocked()); // better not be locked!
-#endif
- if (ll_apr_is_initialized())
- {
- apr_thread_mutex_destroy(mAPRMutexp);
- if (mIsLocalPool)
- {
- apr_pool_destroy(mAPRPoolp);
- }
- }
- mAPRMutexp = NULL;
}
@@ -76,7 +51,7 @@ void LLMutex::lock()
return;
}
- apr_thread_mutex_lock(mAPRMutexp);
+ mMutex.lock();
#if MUTEX_DEBUG
// Have to have the lock before we can access the debug info
@@ -106,19 +81,18 @@ void LLMutex::unlock()
#endif
mLockingThread = NO_THREAD;
- apr_thread_mutex_unlock(mAPRMutexp);
+ mMutex.unlock();
}
bool LLMutex::isLocked()
{
- apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
- if (APR_STATUS_IS_EBUSY(status))
+ if (!mMutex.try_lock())
{
return true;
}
else
{
- apr_thread_mutex_unlock(mAPRMutexp);
+ mMutex.unlock();
return false;
}
}
@@ -141,8 +115,7 @@ bool LLMutex::trylock()
return true;
}
- apr_status_t status(apr_thread_mutex_trylock(mAPRMutexp));
- if (APR_STATUS_IS_EBUSY(status))
+ if (!mMutex.try_lock())
{
return false;
}
@@ -161,45 +134,95 @@ bool LLMutex::trylock()
//============================================================================
-LLCondition::LLCondition(apr_pool_t *poolp) :
- LLMutex(poolp)
+LLCondition::LLCondition() :
+ LLMutex()
{
- // base class (LLMutex) has already ensured that mAPRPoolp is set up.
-
- apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
}
LLCondition::~LLCondition()
{
- apr_thread_cond_destroy(mAPRCondp);
- mAPRCondp = NULL;
}
void LLCondition::wait()
{
- if (!isLocked())
- { //mAPRMutexp MUST be locked before calling apr_thread_cond_wait
- apr_thread_mutex_lock(mAPRMutexp);
-#if MUTEX_DEBUG
- // avoid asserts on destruction in non-release builds
- U32 id = LLThread::currentID();
- mIsLocked[id] = TRUE;
-#endif
- }
- apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
+ std::unique_lock< std::mutex > lock(mMutex);
+ mCond.wait(lock);
}
void LLCondition::signal()
{
- apr_thread_cond_signal(mAPRCondp);
+ mCond.notify_one();
}
void LLCondition::broadcast()
{
- apr_thread_cond_broadcast(mAPRCondp);
+ mCond.notify_all();
+}
+
+
+
+LLMutexTrylock::LLMutexTrylock(LLMutex* mutex)
+ : mMutex(mutex),
+ mLocked(false)
+{
+ if (mMutex)
+ mLocked = mMutex->trylock();
+}
+
+LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
+ : mMutex(mutex),
+ mLocked(false)
+{
+ if (!mMutex)
+ return;
+
+ for (U32 i = 0; i < aTries; ++i)
+ {
+ mLocked = mMutex->trylock();
+ if (mLocked)
+ break;
+ ms_sleep(delay_ms);
+ }
}
+LLMutexTrylock::~LLMutexTrylock()
+{
+ if (mMutex && mLocked)
+ mMutex->unlock();
+}
+
+
+//---------------------------------------------------------------------
+//
+// LLScopedLock
+//
+LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex)
+{
+ if(mutex)
+ {
+ mutex->lock();
+ mLocked = true;
+ }
+ else
+ {
+ mLocked = false;
+ }
+}
+
+LLScopedLock::~LLScopedLock()
+{
+ unlock();
+}
+
+void LLScopedLock::unlock()
+{
+ if(mLocked)
+ {
+ mMutex->unlock();
+ mLocked = false;
+ }
+}
//============================================================================
diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h
index ea535cee86..f841d7f950 100644
--- a/indra/llcommon/llmutex.h
+++ b/indra/llcommon/llmutex.h
@@ -28,6 +28,19 @@
#define LL_LLMUTEX_H
#include "stdtypes.h"
+#include <boost/noncopyable.hpp>
+
+#if LL_WINDOWS
+#pragma warning (push)
+#pragma warning (disable:4265)
+#endif
+// 'std::_Pad' : class has virtual functions, but destructor is not virtual
+#include <mutex>
+#include <condition_variable>
+
+#if LL_WINDOWS
+#pragma warning (pop)
+#endif
//============================================================================
@@ -37,10 +50,6 @@
#include <map>
#endif
-struct apr_thread_mutex_t;
-struct apr_pool_t;
-struct apr_thread_cond_t;
-
class LL_COMMON_API LLMutex
{
public:
@@ -49,7 +58,7 @@ public:
NO_THREAD = 0xFFFFFFFF
} e_locking_thread;
- LLMutex(apr_pool_t *apr_poolp = NULL); // NULL pool constructs a new pool for the mutex
+ LLMutex();
virtual ~LLMutex();
void lock(); // blocks
@@ -60,13 +69,10 @@ public:
U32 lockingThread() const; //get ID of locking thread
protected:
- apr_thread_mutex_t *mAPRMutexp;
+ std::mutex mMutex;
mutable U32 mCount;
mutable U32 mLockingThread;
- apr_pool_t *mAPRPoolp;
- BOOL mIsLocalPool;
-
#if MUTEX_DEBUG
std::map<U32, BOOL> mIsLocked;
#endif
@@ -76,7 +82,7 @@ protected:
class LL_COMMON_API LLCondition : public LLMutex
{
public:
- LLCondition(apr_pool_t* apr_poolp); // Defaults to global pool, could use the thread pool as well.
+ LLCondition();
~LLCondition();
void wait(); // blocks
@@ -84,7 +90,7 @@ public:
void broadcast();
protected:
- apr_thread_cond_t* mAPRCondp;
+ std::condition_variable mCond;
};
class LLMutexLock
@@ -119,19 +125,9 @@ private:
class LLMutexTrylock
{
public:
- LLMutexTrylock(LLMutex* mutex)
- : mMutex(mutex),
- mLocked(false)
- {
- if (mMutex)
- mLocked = mMutex->trylock();
- }
-
- ~LLMutexTrylock()
- {
- if (mMutex && mLocked)
- mMutex->unlock();
- }
+ LLMutexTrylock(LLMutex* mutex);
+ LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms = 10);
+ ~LLMutexTrylock();
bool isLocked() const
{
@@ -142,4 +138,43 @@ private:
LLMutex* mMutex;
bool mLocked;
};
-#endif // LL_LLTHREAD_H
+
+/**
+* @class LLScopedLock
+* @brief Small class to help lock and unlock mutexes.
+*
+* The constructor handles the lock, and the destructor handles
+* the unlock. Instances of this class are <b>not</b> thread safe.
+*/
+class LL_COMMON_API LLScopedLock : private boost::noncopyable
+{
+public:
+ /**
+ * @brief Constructor which accepts a mutex, and locks it.
+ *
+ * @param mutex An allocated mutex. If you pass in NULL,
+ * this wrapper will not lock.
+ */
+ LLScopedLock(std::mutex* mutex);
+
+ /**
+ * @brief Destructor which unlocks the mutex if still locked.
+ */
+ ~LLScopedLock();
+
+ /**
+ * @brief Check lock.
+ */
+ bool isLocked() const { return mLocked; }
+
+ /**
+ * @brief This method unlocks the mutex.
+ */
+ void unlock();
+
+protected:
+ bool mLocked;
+ std::mutex* mMutex;
+};
+
+#endif // LL_LLMUTEX_H
diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index 2879038c36..e8f9981437 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -101,6 +101,9 @@
#endif
+// Although thread_local is now a standard storage class, we can't just
+// #define LL_THREAD_LOCAL as thread_local because the *usage* is different.
+// We'll have to take the time to change LL_THREAD_LOCAL declarations by hand.
#if LL_WINDOWS
# define LL_THREAD_LOCAL __declspec(thread)
#else
@@ -177,6 +180,24 @@
#define LL_DLLIMPORT
#endif // LL_WINDOWS
+#if ! defined(LL_WINDOWS)
+#define LL_WCHAR_T_NATIVE 1
+#else // LL_WINDOWS
+// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
+// _WCHAR_T_DEFINED is defined if wchar_t is provided at all.
+// Specifically, it has value 1 if wchar_t is an intrinsic type, else empty.
+// _NATIVE_WCHAR_T_DEFINED has value 1 if wchar_t is intrinsic, else undefined.
+// For years we have compiled with /Zc:wchar_t-, meaning that wchar_t is a
+// typedef for unsigned short (in stddef.h). Lore has it that one of our
+// proprietary binary-only libraries has traditionally been built that way and
+// therefore EVERYTHING ELSE requires it. Therefore, in a typical Linden
+// Windows build, _WCHAR_T_DEFINED is defined but empty, while
+// _NATIVE_WCHAR_T_DEFINED is undefined.
+# if defined(_NATIVE_WCHAR_T_DEFINED)
+# define LL_WCHAR_T_NATIVE 1
+# endif // _NATIVE_WCHAR_T_DEFINED
+#endif // LL_WINDOWS
+
#if LL_COMMON_LINK_SHARED
// CMake automagically defines llcommon_EXPORTS only when building llcommon
// sources, and only when llcommon is a shared library (i.e. when
@@ -198,6 +219,8 @@
#define LL_TO_STRING_HELPER(x) #x
#define LL_TO_STRING(x) LL_TO_STRING_HELPER(x)
+#define LL_TO_WSTRING_HELPER(x) L#x
+#define LL_TO_WSTRING(x) LL_TO_WSTRING_HELPER(x)
#define LL_FILE_LINENO_MSG(msg) __FILE__ "(" LL_TO_STRING(__LINE__) ") : " msg
#define LL_GLUE_IMPL(x, y) x##y
#define LL_GLUE_TOKENS(x, y) LL_GLUE_IMPL(x, y)
diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp
index 5753efdc59..1fa53f322b 100644
--- a/indra/llcommon/llprocess.cpp
+++ b/indra/llcommon/llprocess.cpp
@@ -1205,30 +1205,9 @@ static LLProcess::Status interpret_status(int status)
/// GetLastError()/FormatMessage() boilerplate
static std::string WindowsErrorString(const std::string& operation)
{
- int result = GetLastError();
-
- LPTSTR error_str = 0;
- if (FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- result,
- 0,
- (LPTSTR)&error_str,
- 0,
- NULL)
- != 0)
- {
- // convert from wide-char string to multi-byte string
- char message[256];
- wcstombs(message, error_str, sizeof(message));
- message[sizeof(message)-1] = 0;
- LocalFree(error_str);
- // convert to std::string to trim trailing whitespace
- std::string mbsstr(message);
- mbsstr.erase(mbsstr.find_last_not_of(" \t\r\n"));
- return STRINGIZE(operation << " failed (" << result << "): " << mbsstr);
- }
- return STRINGIZE(operation << " failed (" << result
- << "), but FormatMessage() did not explain");
+ auto result = GetLastError();
+ return STRINGIZE(operation << " failed (" << result << "): "
+ << windows_message<std::string>(result));
}
/*****************************************************************************
diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h
index d3704b0fe2..5d3f873646 100644
--- a/indra/llcommon/llqueuedthread.h
+++ b/indra/llcommon/llqueuedthread.h
@@ -32,7 +32,7 @@
#include <map>
#include <set>
-#include "llapr.h"
+#include "llatomic.h"
#include "llthread.h"
#include "llsimplehash.h"
@@ -128,7 +128,7 @@ public:
};
protected:
- LLAtomic32<status_t> mStatus;
+ LLAtomicBase<status_t> mStatus;
U32 mPriority;
U32 mFlags;
};
@@ -198,7 +198,7 @@ public:
protected:
BOOL mThreaded; // if false, run on main thread and do updates during update()
BOOL mStarted; // required when mThreaded is false to call startThread() from update()
- LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
+ LLAtomicBool mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
request_queue_t mRequestQueue;
diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp
index a638df2c7c..29a5ca6f24 100644
--- a/indra/llcommon/llrefcount.cpp
+++ b/indra/llcommon/llrefcount.cpp
@@ -29,25 +29,9 @@
#include "llerror.h"
-#if LL_REF_COUNT_DEBUG
-#include "llthread.h"
-#include "llapr.h"
-#endif
-
LLRefCount::LLRefCount(const LLRefCount& other)
: mRef(0)
{
-#if LL_REF_COUNT_DEBUG
- if(gAPRPoolp)
- {
- mMutexp = new LLMutex(gAPRPoolp) ;
- }
- else
- {
- mMutexp = NULL ;
- }
- mCrashAtUnlock = FALSE ;
-#endif
}
LLRefCount& LLRefCount::operator=(const LLRefCount&)
@@ -59,17 +43,6 @@ LLRefCount& LLRefCount::operator=(const LLRefCount&)
LLRefCount::LLRefCount() :
mRef(0)
{
-#if LL_REF_COUNT_DEBUG
- if(gAPRPoolp)
- {
- mMutexp = new LLMutex(gAPRPoolp) ;
- }
- else
- {
- mMutexp = NULL ;
- }
- mCrashAtUnlock = FALSE ;
-#endif
}
LLRefCount::~LLRefCount()
@@ -78,87 +51,5 @@ LLRefCount::~LLRefCount()
{
LL_ERRS() << "deleting non-zero reference" << LL_ENDL;
}
-
-#if LL_REF_COUNT_DEBUG
- if(gAPRPoolp)
- {
- delete mMutexp ;
- }
-#endif
}
-#if LL_REF_COUNT_DEBUG
-void LLRefCount::ref() const
-{
- if(mMutexp)
- {
- if(mMutexp->isLocked())
- {
- mCrashAtUnlock = TRUE ;
- LL_ERRS() << "the mutex is locked by the thread: " << mLockedThreadID
- << " Current thread: " << LLThread::currentID() << LL_ENDL ;
- }
-
- mMutexp->lock() ;
- mLockedThreadID = LLThread::currentID() ;
-
- mRef++;
-
- if(mCrashAtUnlock)
- {
- while(1); //crash here.
- }
- mMutexp->unlock() ;
- }
- else
- {
- mRef++;
- }
-}
-
-S32 LLRefCount::unref() const
-{
- if(mMutexp)
- {
- if(mMutexp->isLocked())
- {
- mCrashAtUnlock = TRUE ;
- LL_ERRS() << "the mutex is locked by the thread: " << mLockedThreadID
- << " Current thread: " << LLThread::currentID() << LL_ENDL ;
- }
-
- mMutexp->lock() ;
- mLockedThreadID = LLThread::currentID() ;
-
- llassert(mRef >= 1);
- if (0 == --mRef)
- {
- if(mCrashAtUnlock)
- {
- while(1); //crash here.
- }
- mMutexp->unlock() ;
-
- delete this;
- return 0;
- }
-
- if(mCrashAtUnlock)
- {
- while(1); //crash here.
- }
- mMutexp->unlock() ;
- return mRef;
- }
- else
- {
- llassert(mRef >= 1);
- if (0 == --mRef)
- {
- delete this;
- return 0;
- }
- return mRef;
- }
-}
-#endif
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index 1107973569..fb0411d27b 100644
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -29,12 +29,7 @@
#include <boost/noncopyable.hpp>
#include <boost/intrusive_ptr.hpp>
#include "llmutex.h"
-#include "llapr.h"
-
-#define LL_REF_COUNT_DEBUG 0
-#if LL_REF_COUNT_DEBUG
-class LLMutex ;
-#endif
+#include "llatomic.h"
//----------------------------------------------------------------------------
// RefCount objects should generally only be accessed by way of LLPointer<>'s
@@ -51,10 +46,6 @@ protected:
public:
LLRefCount();
-#if LL_REF_COUNT_DEBUG
- void ref() const ;
- S32 unref() const ;
-#else
inline void ref() const
{
mRef++;
@@ -69,8 +60,7 @@ public:
return 0;
}
return mRef;
- }
-#endif
+ }
//NOTE: when passing around a const LLRefCount object, this can return different results
// at different types, since mRef is mutable
@@ -81,12 +71,6 @@ public:
private:
mutable S32 mRef;
-
-#if LL_REF_COUNT_DEBUG
- LLMutex* mMutexp ;
- mutable U32 mLockedThreadID ;
- mutable BOOL mCrashAtUnlock ;
-#endif
};
@@ -123,8 +107,8 @@ public:
void unref()
{
llassert(mRef >= 1);
- if ((--mRef) == 0) // See note in llapr.h on atomic decrement operator return value.
- {
+ if ((--mRef) == 0)
+ {
// If we hit zero, the caller should be the only smart pointer owning the object and we can delete it.
// It is technically possible for a vanilla pointer to mess this up, or another thread to
// jump in, find this object, create another smart pointer and end up dangling, but if
@@ -140,7 +124,7 @@ public:
}
private:
- LLAtomic32< S32 > mRef;
+ LLAtomicS32 mRef;
};
/**
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 9a02fecd72..0174c411b4 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -30,6 +30,7 @@
#include "llerror.h"
#include "llfasttimer.h"
#include "llsd.h"
+#include <vector>
#if LL_WINDOWS
#include "llwin32headerslean.h"
@@ -672,6 +673,11 @@ namespace snprintf_hack
}
}
+std::string ll_convert_wide_to_string(const wchar_t* in)
+{
+ return ll_convert_wide_to_string(in, CP_UTF8);
+}
+
std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
{
std::string out;
@@ -709,7 +715,12 @@ std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
return out;
}
-wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page)
+std::wstring ll_convert_string_to_wide(const std::string& in)
+{
+ return ll_convert_string_to_wide(in, CP_UTF8);
+}
+
+std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_page)
{
// From review:
// We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input,
@@ -719,28 +730,148 @@ wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page
// but we *are* seeing string operations taking a bunch of time, especially when constructing widgets.
// int output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(), NULL, 0);
- // reserve place to NULL terminator
- int output_str_len = in.length();
- wchar_t* w_out = new wchar_t[output_str_len + 1];
+ // reserve an output buffer that will be destroyed on exit, with a place
+ // to put NULL terminator
+ std::vector<wchar_t> w_out(in.length() + 1);
- memset(w_out, 0, output_str_len + 1);
- int real_output_str_len = MultiByteToWideChar (code_page, 0, in.c_str(), in.length(), w_out, output_str_len);
+ memset(&w_out[0], 0, w_out.size());
+ int real_output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(),
+ &w_out[0], w_out.size() - 1);
//looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858.
w_out[real_output_str_len] = 0;
- return w_out;
+ // construct string<wchar_t> from our temporary output buffer
+ return {&w_out[0]};
+}
+
+LLWString ll_convert_wide_to_wstring(const std::wstring& in)
+{
+ // This function, like its converse, is a placeholder, encapsulating a
+ // guilty little hack: the only "official" way nat has found to convert
+ // between std::wstring (16 bits on Windows) and LLWString (UTF-32) is
+ // by using iconv, which we've avoided so far. It kinda sorta works to
+ // just copy individual characters...
+ // The point is that if/when we DO introduce some more official way to
+ // perform such conversions, we should only have to call it here.
+ return { in.begin(), in.end() };
+}
+
+std::wstring ll_convert_wstring_to_wide(const LLWString& in)
+{
+ // See comments in ll_convert_wide_to_wstring()
+ return { in.begin(), in.end() };
}
std::string ll_convert_string_to_utf8_string(const std::string& in)
{
- wchar_t* w_mesg = ll_convert_string_to_wide(in, CP_ACP);
- std::string out_utf8(ll_convert_wide_to_string(w_mesg, CP_UTF8));
- delete[] w_mesg;
+ auto w_mesg = ll_convert_string_to_wide(in, CP_ACP);
+ std::string out_utf8(ll_convert_wide_to_string(w_mesg.c_str(), CP_UTF8));
return out_utf8;
}
-#endif // LL_WINDOWS
+
+namespace
+{
+
+void HeapFree_deleter(void* ptr)
+{
+ // instead of LocalFree(), per https://stackoverflow.com/a/31541205
+ HeapFree(GetProcessHeap(), NULL, ptr);
+}
+
+} // anonymous namespace
+
+template<>
+std::wstring windows_message<std::wstring>(DWORD error)
+{
+ // derived from https://stackoverflow.com/a/455533
+ wchar_t* rawptr = nullptr;
+ auto okay = FormatMessageW(
+ // use system message tables for GetLastError() codes
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ // internally allocate buffer and return its pointer
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ // you cannot pass insertion parameters (thanks Gandalf)
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ // ignore line breaks in message definition text
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL, // lpSource, unused with FORMAT_MESSAGE_FROM_SYSTEM
+ error, // dwMessageId
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // dwLanguageId
+ (LPWSTR)&rawptr, // lpBuffer: force-cast wchar_t** to wchar_t*
+ 0, // nSize, unused with FORMAT_MESSAGE_ALLOCATE_BUFFER
+ NULL); // Arguments, unused
+
+ // make a unique_ptr from rawptr so it gets cleaned up properly
+ std::unique_ptr<wchar_t, void(*)(void*)> bufferptr(rawptr, HeapFree_deleter);
+
+ if (okay && bufferptr)
+ {
+ // got the message, return it ('okay' is length in characters)
+ return { bufferptr.get(), okay };
+ }
+
+ // did not get the message, synthesize one
+ auto format_message_error = GetLastError();
+ std::wostringstream out;
+ out << L"GetLastError() " << error << L" (FormatMessageW() failed with "
+ << format_message_error << L")";
+ return out.str();
+}
+
+boost::optional<std::wstring> llstring_getoptenv(const std::string& key)
+{
+ auto wkey = ll_convert_string_to_wide(key);
+ // Take a wild guess as to how big the buffer should be.
+ std::vector<wchar_t> buffer(1024);
+ auto n = GetEnvironmentVariableW(wkey.c_str(), &buffer[0], buffer.size());
+ // If our initial guess was too short, n will indicate the size (in
+ // wchar_t's) that buffer should have been, including the terminating nul.
+ if (n > (buffer.size() - 1))
+ {
+ // make it big enough
+ buffer.resize(n);
+ // and try again
+ n = GetEnvironmentVariableW(wkey.c_str(), &buffer[0], buffer.size());
+ }
+ // did that (ultimately) succeed?
+ if (n)
+ {
+ // great, return populated boost::optional
+ return boost::optional<std::wstring>(&buffer[0]);
+ }
+
+ // not successful
+ auto last_error = GetLastError();
+ // Don't bother warning for NOT_FOUND; that's an expected case
+ if (last_error != ERROR_ENVVAR_NOT_FOUND)
+ {
+ LL_WARNS() << "GetEnvironmentVariableW('" << key << "') failed: "
+ << windows_message<std::string>(last_error) << LL_ENDL;
+ }
+ // return empty boost::optional
+ return {};
+}
+
+#else // ! LL_WINDOWS
+
+boost::optional<std::string> llstring_getoptenv(const std::string& key)
+{
+ auto found = getenv(key.c_str());
+ if (found)
+ {
+ // return populated boost::optional
+ return boost::optional<std::string>(found);
+ }
+ else
+ {
+ // return empty boost::optional
+ return {};
+ }
+}
+
+#endif // ! LL_WINDOWS
long LLStringOps::sPacificTimeOffset = 0;
long LLStringOps::sLocalTimeOffset = 0;
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 68ee9db46b..30bec3a6f8 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -27,6 +27,7 @@
#ifndef LL_LLSTRING_H
#define LL_LLSTRING_H
+#include <boost/optional/optional.hpp>
#include <string>
#include <cstdio>
//#include <locale>
@@ -337,6 +338,19 @@ public:
const string_type& string,
const string_type& substr);
+ /**
+ * get environment string value with proper Unicode handling
+ * (key is always UTF-8)
+ * detect absence by return value == dflt
+ */
+ static string_type getenv(const std::string& key, const string_type& dflt="");
+ /**
+ * get optional environment string value with proper Unicode handling
+ * (key is always UTF-8)
+ * detect absence by (! return value)
+ */
+ static boost::optional<string_type> getoptenv(const std::string& key);
+
static void addCRLF(string_type& string);
static void removeCRLF(string_type& string);
static void removeWindowsCR(string_type& string);
@@ -496,6 +510,37 @@ LL_COMMON_API bool iswindividual(llwchar elem);
* Unicode support
*/
+/// generic conversion aliases
+template<typename TO, typename FROM, typename Enable=void>
+struct ll_convert_impl
+{
+ // Don't even provide a generic implementation. We specialize for every
+ // combination we do support.
+ TO operator()(const FROM& in) const;
+};
+
+// Use a function template to get the nice ll_convert<TO>(from_value) API.
+template<typename TO, typename FROM>
+TO ll_convert(const FROM& in)
+{
+ return ll_convert_impl<TO, FROM>()(in);
+}
+
+// degenerate case
+template<typename T>
+struct ll_convert_impl<T, T>
+{
+ T operator()(const T& in) const { return in; }
+};
+
+// specialize ll_convert_impl<TO, FROM> to return EXPR
+#define ll_convert_alias(TO, FROM, EXPR) \
+template<> \
+struct ll_convert_impl<TO, FROM> \
+{ \
+ TO operator()(const FROM& in) const { return EXPR; } \
+}
+
// Make the incoming string a utf8 string. Replaces any unknown glyph
// with the UNKNOWN_CHARACTER. Once any unknown glyph is found, the rest
// of the data may not be recovered.
@@ -503,30 +548,88 @@ LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw);
//
// We should never use UTF16 except when communicating with Win32!
+// https://docs.microsoft.com/en-us/cpp/cpp/char-wchar-t-char16-t-char32-t
+// nat 2018-12-14: I consider the whole llutf16string thing a mistake, because
+// the Windows APIs we want to call are all defined in terms of wchar_t*
+// (or worse, LPCTSTR).
+// https://docs.microsoft.com/en-us/windows/desktop/winprog/windows-data-types
+
+// While there is no point coding for an ASCII-only world (! defined(UNICODE)),
+// use of U16 and llutf16string for Windows APIs locks in /Zc:wchar_t-. Going
+// forward, we should code in terms of wchar_t and std::wstring so as to
+// support either setting of /Zc:wchar_t.
+
+// The first link above states that char can be used to hold ASCII or any
+// multi-byte character set, and distinguishes wchar_t (UTF-16LE), char16_t
+// (UTF-16) and char32_t (UTF-32). Nonetheless, within this code base:
+// * char and std::string always hold UTF-8 (of which ASCII is a subset). It
+// is a BUG if they are used to pass strings in any other multi-byte
+// encoding.
+// * wchar_t and std::wstring should be our interface to Windows wide-string
+// APIs, and therefore hold UTF-16LE.
+// * U16 and llutf16string are the previous but DEPRECATED UTF-16LE type. Do
+// not introduce new uses of U16 or llutf16string for string data.
+// * llwchar and LLWString hold UTF-32 strings.
+// * Do not introduce char16_t or std::u16string.
+// * Do not introduce char32_t or std::u32string.
//
+// This typedef may or may not be identical to std::wstring, depending on
+// LL_WCHAR_T_NATIVE.
typedef std::basic_string<U16> llutf16string;
+#if ! defined(LL_WCHAR_T_NATIVE)
+// wchar_t is identical to U16, and std::wstring is identical to llutf16string.
+// Defining an ll_convert alias involving llutf16string would collide with the
+// comparable preferred alias involving std::wstring. (In this scenario, if
+// you pass llutf16string, it will engage the std::wstring specialization.)
+#define ll_convert_u16_alias(TO, FROM, EXPR) // nothing
+#else // defined(LL_WCHAR_T_NATIVE)
+// wchar_t is a distinct native type, so llutf16string is also a distinct
+// type, and there IS a point to converting separately to/from llutf16string.
+// (But why? Windows APIs are still defined in terms of wchar_t, and
+// in this scenario llutf16string won't work for them!)
+#define ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
+
+#if LL_WINDOWS
+// LL_WCHAR_T_NATIVE is defined on non-Windows systems because, in fact,
+// wchar_t is native. Everywhere but Windows, we use it for llwchar (see
+// stdtypes.h). That makes LLWString identical to std::wstring, so these
+// aliases for std::wstring would collide with those for LLWString. Only
+// define on Windows, where converting between std::wstring and llutf16string
+// means copying chars.
+ll_convert_alias(llutf16string, std::wstring, llutf16string(in.begin(), in.end()));
+ll_convert_alias(std::wstring, llutf16string, std::wstring(in.begin(), in.end()));
+#endif // LL_WINDOWS
+#endif // defined(LL_WCHAR_T_NATIVE)
+
LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str);
+ll_convert_u16_alias(LLWString, llutf16string, utf16str_to_wstring(in));
LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str);
+ll_convert_u16_alias(llutf16string, LLWString, wstring_to_utf16str(in));
LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len);
LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str );
+ll_convert_u16_alias(llutf16string, std::string, utf8str_to_utf16str(in));
LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str);
// Same function, better name. JC
inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
+// best name of all
+ll_convert_alias(LLWString, std::string, utf8string_to_wstring(in));
//
LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str);
+ll_convert_alias(std::string, LLWString, wstring_to_utf8str(in));
LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str);
+ll_convert_u16_alias(std::string, llutf16string, utf16str_to_utf8str(in));
#if LL_WINDOWS
inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);}
@@ -635,22 +738,77 @@ using snprintf_hack::snprintf;
* This replaces the unsafe W2A macro from ATL.
*/
LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page);
+LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); // default CP_UTF8
+inline std::string ll_convert_wide_to_string(const std::wstring& in, unsigned int code_page)
+{
+ return ll_convert_wide_to_string(in.c_str(), code_page);
+}
+inline std::string ll_convert_wide_to_string(const std::wstring& in)
+{
+ return ll_convert_wide_to_string(in.c_str());
+}
+ll_convert_alias(std::string, std::wstring, ll_convert_wide_to_string(in));
/**
* Converts a string to wide string.
- *
- * It will allocate memory for result string with "new []". Don't forget to release it with "delete []".
*/
-LL_COMMON_API wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page);
+LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in,
+ unsigned int code_page);
+LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in);
+ // default CP_UTF8
+ll_convert_alias(std::wstring, std::string, ll_convert_string_to_wide(in));
/**
- * Converts incoming string into urf8 string
+ * Convert a Windows wide string to our LLWString
+ */
+LL_COMMON_API LLWString ll_convert_wide_to_wstring(const std::wstring& in);
+ll_convert_alias(LLWString, std::wstring, ll_convert_wide_to_wstring(in));
+
+/**
+ * Convert LLWString to Windows wide string
+ */
+LL_COMMON_API std::wstring ll_convert_wstring_to_wide(const LLWString& in);
+ll_convert_alias(std::wstring, LLWString, ll_convert_wstring_to_wide(in));
+
+/**
+ * Converts incoming string into utf8 string
*
*/
LL_COMMON_API std::string ll_convert_string_to_utf8_string(const std::string& in);
+/// Get Windows message string for passed GetLastError() code
+// VS 2013 doesn't let us forward-declare this template, which is what we
+// started with, so the implementation could reference the specialization we
+// haven't yet declared. Somewhat weirdly, just stating the generic
+// implementation in terms of the specialization works, even in this order...
+
+// the general case is just a conversion from the sole implementation
+// Microsoft says DWORD is a typedef for unsigned long
+// https://docs.microsoft.com/en-us/windows/desktop/winprog/windows-data-types
+// so rather than drag windows.h into everybody's include space...
+template<typename STRING>
+STRING windows_message(unsigned long error)
+{
+ return ll_convert<STRING>(windows_message<std::wstring>(error));
+}
+
+/// There's only one real implementation
+template<>
+LL_COMMON_API std::wstring windows_message<std::wstring>(unsigned long error);
+
+/// Get Windows message string, implicitly calling GetLastError()
+template<typename STRING>
+STRING windows_message() { return windows_message<STRING>(GetLastError()); }
+
//@}
-#endif // LL_WINDOWS
+
+LL_COMMON_API boost::optional<std::wstring> llstring_getoptenv(const std::string& key);
+
+#else // ! LL_WINDOWS
+
+LL_COMMON_API boost::optional<std::string> llstring_getoptenv(const std::string& key);
+
+#endif // ! LL_WINDOWS
/**
* Many of the 'strip' and 'replace' methods of LLStringUtilBase need
@@ -1593,6 +1751,37 @@ bool LLStringUtilBase<T>::endsWith(
return (idx == (string.size() - substr.size()));
}
+// static
+template<class T>
+auto LLStringUtilBase<T>::getoptenv(const std::string& key) -> boost::optional<string_type>
+{
+ auto found(llstring_getoptenv(key));
+ if (found)
+ {
+ // return populated boost::optional
+ return { ll_convert<string_type>(*found) };
+ }
+ else
+ {
+ // empty boost::optional
+ return {};
+ }
+}
+
+// static
+template<class T>
+auto LLStringUtilBase<T>::getenv(const std::string& key, const string_type& dflt) -> string_type
+{
+ auto found(getoptenv(key));
+ if (found)
+ {
+ return *found;
+ }
+ else
+ {
+ return dflt;
+ }
+}
template<class T>
BOOL LLStringUtilBase<T>::convertToBOOL(const string_type& string, BOOL& value)
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 1ef6c538ba..1f8d558fbe 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -268,10 +268,32 @@ LLOSInfo::LLOSInfo() :
}
}
+ S32 ubr = 0; // Windows 10 Update Build Revision, can be retrieved from a registry
+ if (mMajorVer == 10)
+ {
+ DWORD cbData(sizeof(DWORD));
+ DWORD data(0);
+ HKEY key;
+ BOOL ret_code = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_READ, &key);
+ if (ERROR_SUCCESS == ret_code)
+ {
+ ret_code = RegQueryValueExW(key, L"UBR", 0, NULL, reinterpret_cast<LPBYTE>(&data), &cbData);
+ if (ERROR_SUCCESS == ret_code)
+ {
+ ubr = data;
+ }
+ }
+ }
+
mOSString = mOSStringSimple;
if (mBuild > 0)
{
- mOSString += llformat("(Build %d)", mBuild);
+ mOSString += llformat("(Build %d", mBuild);
+ if (ubr > 0)
+ {
+ mOSString += llformat(".%d", ubr);
+ }
+ mOSString += ")";
}
LLStringUtil::trim(mOSStringSimple);
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index f066e9a4cd..a4171729db 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -116,29 +116,27 @@ void LLThread::registerThreadID()
//
// Handed to the APR thread creation function
//
-void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap)
+void LLThread::threadRun()
{
- LLThread *threadp = (LLThread *)datap;
-
#ifdef LL_WINDOWS
- set_thread_name(-1, threadp->mName.c_str());
+ set_thread_name(-1, mName.c_str());
#endif
// for now, hard code all LLThreads to report to single master thread recorder, which is known to be running on main thread
- threadp->mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder());
+ mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder());
- sThreadID = threadp->mID;
+ sThreadID = mID;
// Run the user supplied function
do
{
try
{
- threadp->run();
+ run();
}
catch (const LLContinueError &e)
{
- LL_WARNS("THREAD") << "ContinueException on thread '" << threadp->mName <<
+ LL_WARNS("THREAD") << "ContinueException on thread '" << mName <<
"' reentering run(). Error what is: '" << e.what() << "'" << LL_ENDL;
//output possible call stacks to log file.
LLError::LLCallStacks::print();
@@ -153,41 +151,27 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
//LL_INFOS() << "LLThread::staticRun() Exiting: " << threadp->mName << LL_ENDL;
- delete threadp->mRecorder;
- threadp->mRecorder = NULL;
+ delete mRecorder;
+ mRecorder = NULL;
// We're done with the run function, this thread is done executing now.
//NB: we are using this flag to sync across threads...we really need memory barriers here
// Todo: add LLMutex per thread instead of flag?
// We are using "while (mStatus != STOPPED) {ms_sleep();}" everywhere.
- threadp->mStatus = STOPPED;
-
- return NULL;
+ mStatus = STOPPED;
}
LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
mPaused(FALSE),
mName(name),
- mAPRThreadp(NULL),
+ mThreadp(NULL),
mStatus(STOPPED),
mRecorder(NULL)
{
mID = ++sIDIter;
-
- // Thread creation probably CAN be paranoid about APR being initialized, if necessary
- if (poolp)
- {
- mIsLocalPool = FALSE;
- mAPRPoolp = poolp;
- }
- else
- {
- mIsLocalPool = TRUE;
- apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
- }
- mRunCondition = new LLCondition(mAPRPoolp);
- mDataLock = new LLMutex(mAPRPoolp);
+ mRunCondition = new LLCondition();
+ mDataLock = new LLMutex();
mLocalAPRFilePoolp = NULL ;
}
@@ -217,7 +201,7 @@ void LLThread::shutdown()
// Warning! If you somehow call the thread destructor from itself,
// the thread will die in an unclean fashion!
- if (mAPRThreadp)
+ if (mThreadp)
{
if (!isStopped())
{
@@ -248,14 +232,19 @@ void LLThread::shutdown()
{
// This thread just wouldn't stop, even though we gave it time
//LL_WARNS() << "LLThread::~LLThread() exiting thread before clean exit!" << LL_ENDL;
- // Put a stake in its heart.
- apr_thread_exit(mAPRThreadp, -1);
+ // Put a stake in its heart. (A very hostile method to force a thread to quit)
+#if LL_WINDOWS
+ TerminateThread(mNativeHandle, 0);
+#else
+ pthread_cancel(mNativeHandle);
+#endif
+
delete mRecorder;
mRecorder = NULL;
mStatus = STOPPED;
return;
}
- mAPRThreadp = NULL;
+ mThreadp = NULL;
}
delete mRunCondition;
@@ -263,12 +252,6 @@ void LLThread::shutdown()
delete mDataLock;
mDataLock = NULL;
-
- if (mIsLocalPool && mAPRPoolp)
- {
- apr_pool_destroy(mAPRPoolp);
- mAPRPoolp = 0;
- }
if (mRecorder)
{
@@ -287,19 +270,15 @@ void LLThread::start()
// Set thread state to running
mStatus = RUNNING;
- apr_status_t status =
- apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
-
- if(status == APR_SUCCESS)
- {
- // We won't bother joining
- apr_thread_detach(mAPRThreadp);
+ try
+ {
+ mThreadp = new std::thread(std::bind(&LLThread::threadRun, this));
+ mNativeHandle = mThreadp->native_handle();
}
- else
+ catch (std::system_error& ex)
{
mStatus = STOPPED;
- LL_WARNS() << "failed to start thread " << mName << LL_ENDL;
- ll_apr_warn_status(status);
+ LL_WARNS() << "failed to start thread " << mName << " " << ex.what() << LL_ENDL;
}
}
@@ -376,11 +355,7 @@ U32 LLThread::currentID()
// static
void LLThread::yield()
{
-#if LL_LINUX || LL_SOLARIS
- sched_yield(); // annoyingly, apr_thread_yield is a noop on linux...
-#else
- apr_thread_yield();
-#endif
+ std::this_thread::yield();
}
void LLThread::wake()
@@ -413,7 +388,7 @@ void LLThreadSafeRefCount::initThreadSafeRefCount()
{
if (!sMutex)
{
- sMutex = new LLMutex(0);
+ sMutex = new LLMutex();
}
}
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index dda7fa8ffb..863c9051f3 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -29,10 +29,10 @@
#include "llapp.h"
#include "llapr.h"
-#include "apr_thread_cond.h"
#include "boost/intrusive_ptr.hpp"
#include "llmutex.h"
#include "llrefcount.h"
+#include <thread>
LL_COMMON_API void assert_main_thread();
@@ -86,7 +86,6 @@ public:
// this kicks off the apr thread
void start(void);
- apr_pool_t *getAPRPool() { return mAPRPoolp; }
LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
U32 getID() const { return mID; }
@@ -97,19 +96,18 @@ public:
static void registerThreadID();
private:
- BOOL mPaused;
+ bool mPaused;
+ std::thread::native_handle_type mNativeHandle; // for termination in case of issues
// static function passed to APR thread creation routine
- static void *APR_THREAD_FUNC staticRun(struct apr_thread_t *apr_threadp, void *datap);
+ void threadRun();
protected:
std::string mName;
class LLCondition* mRunCondition;
LLMutex* mDataLock;
- apr_thread_t *mAPRThreadp;
- apr_pool_t *mAPRPoolp;
- BOOL mIsLocalPool;
+ std::thread *mThreadp;
EThreadStatus mStatus;
U32 mID;
LLTrace::ThreadRecorder* mRecorder;
diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp
index 491f920c0f..bde36999ba 100644
--- a/indra/llcommon/llthreadsafequeue.cpp
+++ b/indra/llcommon/llthreadsafequeue.cpp
@@ -24,87 +24,6 @@
*/
#include "linden_common.h"
-#include <apr_pools.h>
-#include <apr_queue.h>
#include "llthreadsafequeue.h"
-#include "llexception.h"
-
-// LLThreadSafeQueueImplementation
-//-----------------------------------------------------------------------------
-
-
-LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity):
- mOwnsPool(pool == 0),
- mPool(pool),
- mQueue(0)
-{
- if(mOwnsPool) {
- apr_status_t status = apr_pool_create(&mPool, 0);
- if(status != APR_SUCCESS) LLTHROW(LLThreadSafeQueueError("failed to allocate pool"));
- } else {
- ; // No op.
- }
-
- apr_status_t status = apr_queue_create(&mQueue, capacity, mPool);
- if(status != APR_SUCCESS) LLTHROW(LLThreadSafeQueueError("failed to allocate queue"));
-}
-
-
-LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation()
-{
- if(mQueue != 0) {
- if(apr_queue_size(mQueue) != 0) LL_WARNS() <<
- "terminating queue which still contains " << apr_queue_size(mQueue) <<
- " elements;" << "memory will be leaked" << LL_ENDL;
- apr_queue_term(mQueue);
- }
- if(mOwnsPool && (mPool != 0)) apr_pool_destroy(mPool);
-}
-
-
-void LLThreadSafeQueueImplementation::pushFront(void * element)
-{
- apr_status_t status = apr_queue_push(mQueue, element);
-
- if(status == APR_EINTR) {
- LLTHROW(LLThreadSafeQueueInterrupt());
- } else if(status != APR_SUCCESS) {
- LLTHROW(LLThreadSafeQueueError("push failed"));
- } else {
- ; // Success.
- }
-}
-
-
-bool LLThreadSafeQueueImplementation::tryPushFront(void * element){
- return apr_queue_trypush(mQueue, element) == APR_SUCCESS;
-}
-
-
-void * LLThreadSafeQueueImplementation::popBack(void)
-{
- void * element;
- apr_status_t status = apr_queue_pop(mQueue, &element);
-
- if(status == APR_EINTR) {
- LLTHROW(LLThreadSafeQueueInterrupt());
- } else if(status != APR_SUCCESS) {
- LLTHROW(LLThreadSafeQueueError("pop failed"));
- } else {
- return element;
- }
-}
-
-
-bool LLThreadSafeQueueImplementation::tryPopBack(void *& element)
-{
- return apr_queue_trypop(mQueue, &element) == APR_SUCCESS;
-}
-
-
-size_t LLThreadSafeQueueImplementation::size()
-{
- return apr_queue_size(mQueue);
-}
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 45289ef0b4..b0bddac8e5 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -28,12 +28,20 @@
#define LL_LLTHREADSAFEQUEUE_H
#include "llexception.h"
+#include <deque>
#include <string>
+#if LL_WINDOWS
+#pragma warning (push)
+#pragma warning (disable:4265)
+#endif
+// 'std::_Pad' : class has virtual functions, but destructor is not virtual
+#include <mutex>
+#include <condition_variable>
-struct apr_pool_t; // From apr_pools.h
-class LLThreadSafeQueueImplementation; // See below.
-
+#if LL_WINDOWS
+#pragma warning (pop)
+#endif
//
// A general queue exception.
@@ -64,31 +72,6 @@ public:
}
};
-
-struct apr_queue_t; // From apr_queue.h
-
-
-//
-// Implementation details.
-//
-class LL_COMMON_API LLThreadSafeQueueImplementation
-{
-public:
- LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity);
- ~LLThreadSafeQueueImplementation();
- void pushFront(void * element);
- bool tryPushFront(void * element);
- void * popBack(void);
- bool tryPopBack(void *& element);
- size_t size();
-
-private:
- bool mOwnsPool;
- apr_pool_t * mPool;
- apr_queue_t * mQueue;
-};
-
-
//
// Implements a thread safe FIFO.
//
@@ -100,7 +83,7 @@ public:
// If the pool is set to NULL one will be allocated and managed by this
// queue.
- LLThreadSafeQueue(apr_pool_t * pool = 0, unsigned int capacity = 1024);
+ LLThreadSafeQueue(U32 capacity = 1024);
// Add an element to the front of queue (will block if the queue has
// reached capacity).
@@ -128,77 +111,103 @@ public:
size_t size();
private:
- LLThreadSafeQueueImplementation mImplementation;
-};
-
+ std::deque< ElementT > mStorage;
+ U32 mCapacity;
+ std::mutex mLock;
+ std::condition_variable mCapacityCond;
+ std::condition_variable mEmptyCond;
+};
// LLThreadSafeQueue
//-----------------------------------------------------------------------------
-
template<typename ElementT>
-LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity):
- mImplementation(pool, capacity)
+LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(U32 capacity) :
+mCapacity(capacity)
{
- ; // No op.
}
template<typename ElementT>
void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
{
- ElementT * elementCopy = new ElementT(element);
- try {
- mImplementation.pushFront(elementCopy);
- } catch (LLThreadSafeQueueInterrupt) {
- delete elementCopy;
- throw;
- }
+ while (true)
+ {
+ std::unique_lock<std::mutex> lock1(mLock);
+
+ if (mStorage.size() < mCapacity)
+ {
+ mStorage.push_front(element);
+ mEmptyCond.notify_one();
+ return;
+ }
+
+ // Storage Full. Wait for signal.
+ mCapacityCond.wait(lock1);
+ }
}
template<typename ElementT>
bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
{
- ElementT * elementCopy = new ElementT(element);
- bool result = mImplementation.tryPushFront(elementCopy);
- if(!result) delete elementCopy;
- return result;
+ std::unique_lock<std::mutex> lock1(mLock, std::defer_lock);
+ if (!lock1.try_lock())
+ return false;
+
+ if (mStorage.size() >= mCapacity)
+ return false;
+
+ mStorage.push_front(element);
+ mEmptyCond.notify_one();
+ return true;
}
template<typename ElementT>
ElementT LLThreadSafeQueue<ElementT>::popBack(void)
{
- ElementT * element = reinterpret_cast<ElementT *> (mImplementation.popBack());
- ElementT result(*element);
- delete element;
- return result;
+ while (true)
+ {
+ std::unique_lock<std::mutex> lock1(mLock);
+
+ if (!mStorage.empty())
+ {
+ ElementT value = mStorage.back();
+ mStorage.pop_back();
+ mCapacityCond.notify_one();
+ return value;
+ }
+
+ // Storage empty. Wait for signal.
+ mEmptyCond.wait(lock1);
+ }
}
template<typename ElementT>
bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element)
{
- void * storedElement;
- bool result = mImplementation.tryPopBack(storedElement);
- if(result) {
- ElementT * elementPtr = reinterpret_cast<ElementT *>(storedElement);
- element = *elementPtr;
- delete elementPtr;
- } else {
- ; // No op.
- }
- return result;
+ std::unique_lock<std::mutex> lock1(mLock, std::defer_lock);
+ if (!lock1.try_lock())
+ return false;
+
+ if (mStorage.empty())
+ return false;
+
+ element = mStorage.back();
+ mStorage.pop_back();
+ mCapacityCond.notify_one();
+ return true;
}
template<typename ElementT>
size_t LLThreadSafeQueue<ElementT>::size(void)
{
- return mImplementation.size();
+ std::lock_guard<std::mutex> lock(mLock);
+ return mStorage.size();
}
-
#endif
diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp
index d4af2c6b01..8f33d789eb 100644
--- a/indra/llcommon/lluuid.cpp
+++ b/indra/llcommon/lluuid.cpp
@@ -738,7 +738,7 @@ void LLUUID::getCurrentTime(uuid_time_t *timestamp)
getSystemTime(&time_last);
uuids_this_tick = uuids_per_tick;
init = TRUE;
- mMutex = new LLMutex(NULL);
+ mMutex = new LLMutex();
}
uuid_time_t time_now = {0,0};
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index 4c197dc1d6..4b91b2caca 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -37,7 +37,7 @@
LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) :
LLQueuedThread(name, threaded, should_pause)
{
- mDeleteMutex = new LLMutex(NULL);
+ mDeleteMutex = new LLMutex();
if(!mLocalAPRFilePoolp)
{
@@ -204,7 +204,7 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na
mWorkerClassName(name),
mRequestHandle(LLWorkerThread::nullHandle()),
mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
- mMutex(NULL),
+ mMutex(),
mWorkFlags(0)
{
if (!mWorkerThread)
diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index 09776816a8..b1a6f61360 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -33,7 +33,7 @@
#include <string>
#include "llqueuedthread.h"
-#include "llapr.h"
+#include "llatomic.h"
#define USE_FRAME_CALLBACK_MANAGER 0
diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h
index bf3f3f9ee8..6c9871e76c 100644
--- a/indra/llcommon/stdtypes.h
+++ b/indra/llcommon/stdtypes.h
@@ -37,7 +37,12 @@ typedef signed int S32;
typedef unsigned int U32;
#if LL_WINDOWS
-// Windows wchar_t is 16-bit
+// https://docs.microsoft.com/en-us/cpp/build/reference/zc-wchar-t-wchar-t-is-native-type
+// https://docs.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp
+// Windows wchar_t is 16-bit, whichever way /Zc:wchar_t is set. In effect,
+// Windows wchar_t is always a typedef, either for unsigned short or __wchar_t.
+// (__wchar_t, available either way, is Microsoft's native 2-byte wchar_t type.)
+// In any case, llwchar should be a UTF-32 type.
typedef U32 llwchar;
#else
typedef wchar_t llwchar;
diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h
index a5a90d7297..38dd198ad3 100644
--- a/indra/llcommon/stringize.h
+++ b/indra/llcommon/stringize.h
@@ -30,7 +30,6 @@
#define LL_STRINGIZE_H
#include <sstream>
-#include <boost/phoenix/phoenix.hpp>
#include <llstring.h>
/**
@@ -53,12 +52,7 @@ std::basic_string<CHARTYPE> gstringize(const T& item)
*/
inline std::string stringize(const std::wstring& item)
{
- LL_WARNS() << "WARNING: Possible narrowing" << LL_ENDL;
-
- std::string s;
-
- s = wstring_to_utf8str(item);
- return gstringize<char>(s);
+ return wstring_to_utf8str(item);
}
/**
@@ -76,7 +70,10 @@ std::string stringize(const T& item)
*/
inline std::wstring wstringize(const std::string& item)
{
- return gstringize<wchar_t>(item.c_str());
+ // utf8str_to_wstring() returns LLWString, which isn't necessarily the
+ // same as std::wstring
+ LLWString s(utf8str_to_wstring(item));
+ return std::wstring(s.begin(), s.end());
}
/**
@@ -91,10 +88,10 @@ std::wstring wstringize(const T& item)
/**
* stringize_f(functor)
*/
-template <typename Functor>
-std::string stringize_f(Functor const & f)
+template <typename CHARTYPE, typename Functor>
+std::basic_string<CHARTYPE> stringize_f(Functor const & f)
{
- std::ostringstream out;
+ std::basic_ostringstream<CHARTYPE> out;
f(out);
return out.str();
}
@@ -108,31 +105,37 @@ std::string stringize_f(Functor const & f)
* return out.str();
* @endcode
*/
-#define STRINGIZE(EXPRESSION) (stringize_f(boost::phoenix::placeholders::arg1 << EXPRESSION))
+#define STRINGIZE(EXPRESSION) (stringize_f<char>([&](std::ostream& out){ out << EXPRESSION; }))
+/**
+ * WSTRINGIZE() is the wstring equivalent of STRINGIZE()
+ */
+#define WSTRINGIZE(EXPRESSION) (stringize_f<wchar_t>([&](std::wostream& out){ out << EXPRESSION; }))
/**
* destringize(str)
* defined for symmetry with stringize
- * *NOTE - this has distinct behavior from boost::lexical_cast<T> regarding
+ * @NOTE - this has distinct behavior from boost::lexical_cast<T> regarding
* leading/trailing whitespace and handling of bad_lexical_cast exceptions
+ * @NOTE - no need for dewstringize(), since passing std::wstring will Do The
+ * Right Thing
*/
-template <typename T>
-T destringize(std::string const & str)
+template <typename T, typename CHARTYPE>
+T destringize(std::basic_string<CHARTYPE> const & str)
{
- T val;
- std::istringstream in(str);
- in >> val;
+ T val;
+ std::basic_istringstream<CHARTYPE> in(str);
+ in >> val;
return val;
}
/**
* destringize_f(str, functor)
*/
-template <typename Functor>
-void destringize_f(std::string const & str, Functor const & f)
+template <typename CHARTYPE, typename Functor>
+void destringize_f(std::basic_string<CHARTYPE> const & str, Functor const & f)
{
- std::istringstream in(str);
+ std::basic_istringstream<CHARTYPE> in(str);
f(in);
}
@@ -143,8 +146,11 @@ void destringize_f(std::string const & str, Functor const & f)
* std::istringstream in(str);
* in >> item1 >> item2 >> item3 ... ;
* @endcode
+ * @NOTE - once we get generic lambdas, we shouldn't need DEWSTRINGIZE() any
+ * more since DESTRINGIZE() should do the right thing with a std::wstring. But
+ * until then, the lambda we pass must accept the right std::basic_istream.
*/
-#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), (boost::phoenix::placeholders::arg1 >> EXPRESSION)))
-
+#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::istream& in){in >> EXPRESSION;}))
+#define DEWSTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::wistream& in){in >> EXPRESSION;}))
#endif /* ! defined(LL_STRINGIZE_H) */
diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp
index ce0dbce075..8e1f4c14ac 100644
--- a/indra/llcommon/tests/llerror_test.cpp
+++ b/indra/llcommon/tests/llerror_test.cpp
@@ -78,8 +78,12 @@ namespace tut
class TestRecorder : public LLError::Recorder
{
public:
- TestRecorder() { mWantsTime = false; mWantsTags = true; }
- virtual ~TestRecorder() { }
+ TestRecorder()
+ {
+ showTime(false);
+ }
+ virtual ~TestRecorder()
+ {}
virtual void recordMessage(LLError::ELevel level,
const std::string& message)
@@ -90,8 +94,6 @@ namespace tut
int countMessages() { return (int) mMessages.size(); }
void clearMessages() { mMessages.clear(); }
- void setWantsTime(bool t) { mWantsTime = t; }
-
std::string message(int n)
{
std::ostringstream test_name;
@@ -139,9 +141,14 @@ namespace tut
}
void setWantsTime(bool t)
- {
- boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->setWantsTime(t);
- }
+ {
+ boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->showTime(t);
+ }
+
+ void setWantsMultiline(bool t)
+ {
+ boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->showMultiline(t);
+ }
std::string message(int n)
{
@@ -378,27 +385,6 @@ namespace
}
}
-namespace tut
-{
- template<> template<>
- void ErrorTestObject::test<5>()
- // file and line information in log messages
- {
- std::string location = writeReturningLocation();
- // expecting default to not print location information
-
- LLError::setPrintLocation(true);
- writeReturningLocation();
-
- LLError::setPrintLocation(false);
- writeReturningLocation();
-
- ensure_message_does_not_contain(0, location);
- ensure_message_field_equals(1, LOCATION_FIELD, location);
- ensure_message_does_not_contain(2, location);
- }
-}
-
/* The following helper functions and class members all log a simple message
from some particular function scope. Each function takes a bool argument
that indicates if it should log its own name or not (in the manner that
@@ -512,6 +498,39 @@ namespace
}
}
+namespace
+{
+ void writeMsgNeedsEscaping()
+ {
+ LL_DEBUGS("WriteTag") << "backslash\\" << LL_ENDL;
+ LL_INFOS("WriteTag") << "newline\nafternewline" << LL_ENDL;
+ LL_WARNS("WriteTag") << "return\rafterreturn" << LL_ENDL;
+
+ LL_DEBUGS("WriteTag") << "backslash\\backslash\\" << LL_ENDL;
+ LL_INFOS("WriteTag") << "backslash\\newline\nanothernewline\nafternewline" << LL_ENDL;
+ LL_WARNS("WriteTag") << "backslash\\returnnewline\r\n\\afterbackslash" << LL_ENDL;
+ }
+};
+
+namespace tut
+{
+ template<> template<>
+ void ErrorTestObject::test<5>()
+ // backslash, return, and newline are not escaped with backslashes
+ {
+ LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ setWantsMultiline(true);
+ writeMsgNeedsEscaping(); // but should not be now
+ ensure_message_field_equals(0, MSG_FIELD, "backslash\\");
+ ensure_message_field_equals(1, MSG_FIELD, "newline\nafternewline");
+ ensure_message_field_equals(2, MSG_FIELD, "return\rafterreturn");
+ ensure_message_field_equals(3, MSG_FIELD, "backslash\\backslash\\");
+ ensure_message_field_equals(4, MSG_FIELD, "backslash\\newline\nanothernewline\nafternewline");
+ ensure_message_field_equals(5, MSG_FIELD, "backslash\\returnnewline\r\n\\afterbackslash");
+ ensure_message_count(6);
+ }
+}
+
namespace tut
{
template<> template<>
@@ -583,7 +602,6 @@ namespace tut
// special handling of LL_ERRS() calls
void ErrorTestObject::test<8>()
{
- LLError::setPrintLocation(false);
std::string location = errorReturningLocation();
ensure_message_field_equals(0, LOCATION_FIELD, location);
@@ -630,15 +648,15 @@ namespace tut
// output order
void ErrorTestObject::test<10>()
{
- LLError::setPrintLocation(true);
LLError::setTimeFunction(roswell);
setWantsTime(true);
+
std::string location,
function;
writeReturningLocationAndFunction(location, function);
ensure_equals("order is time level tags location function message",
- message(0),
+ message(0),
roswell() + " INFO " + "# " /* no tag */ + location + " " + function + " : " + "apple");
}
@@ -658,7 +676,7 @@ namespace tut
LLError::setTimeFunction(roswell);
LLError::RecorderPtr anotherRecorder(new TestRecorder());
- boost::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->setWantsTime(true);
+ boost::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->showTime(true);
LLError::addRecorder(anotherRecorder);
LL_INFOS() << "baz" << LL_ENDL;
@@ -835,20 +853,6 @@ namespace tut
}
}
-namespace
-{
- void writeMsgNeedsEscaping()
- {
- LL_DEBUGS("WriteTag") << "backslash\\" << LL_ENDL;
- LL_INFOS("WriteTag") << "newline\nafternewline" << LL_ENDL;
- LL_WARNS("WriteTag") << "return\rafterreturn" << LL_ENDL;
-
- LL_DEBUGS("WriteTag") << "backslash\\backslash\\" << LL_ENDL;
- LL_INFOS("WriteTag") << "backslash\\newline\nanothernewline\nafternewline" << LL_ENDL;
- LL_WARNS("WriteTag") << "backslash\\returnnewline\r\n\\afterbackslash" << LL_ENDL;
- }
-};
-
namespace tut
{
template<> template<>
diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp
index c387da6c48..45648536c4 100644
--- a/indra/llcommon/tests/llleap_test.cpp
+++ b/indra/llcommon/tests/llleap_test.cpp
@@ -26,6 +26,7 @@
#include "wrapllerrs.h"
#include "llevents.h"
#include "llprocess.h"
+#include "llstring.h"
#include "stringize.h"
#include "StringVec.h"
#include <functional>
@@ -198,14 +199,12 @@ namespace tut
// basename.
reader_module(LLProcess::basename(
reader.getName().substr(0, reader.getName().length()-3))),
- pPYTHON(getenv("PYTHON")),
- PYTHON(pPYTHON? pPYTHON : "")
+ PYTHON(LLStringUtil::getenv("PYTHON"))
{
- ensure("Set PYTHON to interpreter pathname", pPYTHON);
+ ensure("Set PYTHON to interpreter pathname", !PYTHON.empty());
}
NamedExtTempFile reader;
const std::string reader_module;
- const char* pPYTHON;
const std::string PYTHON;
};
typedef test_group<llleap_data> llleap_group;
diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index b27e125d2e..5c87cdabd9 100644
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -34,6 +34,7 @@
#include "stringize.h"
#include "llsdutil.h"
#include "llevents.h"
+#include "llstring.h"
#include "wrapllerrs.h"
#if defined(LL_WINDOWS)
@@ -142,8 +143,8 @@ struct PythonProcessLauncher
mDesc(desc),
mScript("py", script)
{
- const char* PYTHON(getenv("PYTHON"));
- tut::ensure("Set $PYTHON to the Python interpreter", PYTHON);
+ auto PYTHON(LLStringUtil::getenv("PYTHON"));
+ tut::ensure("Set $PYTHON to the Python interpreter", !PYTHON.empty());
mParams.desc = desc + " script";
mParams.executable = PYTHON;
diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
index 745e3a168c..6ac974e659 100644
--- a/indra/llcommon/tests/llsdserialize_test.cpp
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -41,6 +41,7 @@ typedef U32 uint32_t;
#include <sys/stat.h>
#include <sys/wait.h>
#include "llprocess.h"
+#include "llstring.h"
#endif
#include "boost/range.hpp"
@@ -1705,8 +1706,8 @@ namespace tut
template <typename CONTENT>
void python(const std::string& desc, const CONTENT& script, int expect=0)
{
- const char* PYTHON(getenv("PYTHON"));
- ensure("Set $PYTHON to the Python interpreter", PYTHON);
+ auto PYTHON(LLStringUtil::getenv("PYTHON"));
+ ensure("Set $PYTHON to the Python interpreter", !PYTHON.empty());
NamedTempFile scriptfile("py", script);
@@ -1714,7 +1715,7 @@ namespace tut
std::string q("\"");
std::string qPYTHON(q + PYTHON + q);
std::string qscript(q + scriptfile.getName() + q);
- int rc = _spawnl(_P_WAIT, PYTHON, qPYTHON.c_str(), qscript.c_str(), NULL);
+ int rc = _spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(), NULL);
if (rc == -1)
{
char buffer[256];
diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h
index 9a4bbbd630..08fbf19b1c 100644
--- a/indra/llcommon/tests/wrapllerrs.h
+++ b/indra/llcommon/tests/wrapllerrs.h
@@ -109,6 +109,12 @@ public:
mMessages.push_back(message);
}
+ friend inline
+ std::ostream& operator<<(std::ostream& out, const CaptureLogRecorder& log)
+ {
+ return log.streamto(out);
+ }
+
/// Don't assume the message we want is necessarily the LAST log message
/// emitted by the underlying code; search backwards through all messages
/// for the sought string.
@@ -126,7 +132,7 @@ public:
throw tut::failure(STRINGIZE("failed to find '" << search
<< "' in captured log messages:\n"
- << boost::ref(*this)));
+ << *this));
}
std::ostream& streamto(std::ostream& out) const
@@ -200,10 +206,4 @@ private:
LLError::RecorderPtr mRecorder;
};
-inline
-std::ostream& operator<<(std::ostream& out, const CaptureLogRecorder& log)
-{
- return log.streamto(out);
-}
-
#endif /* ! defined(LL_WRAPLLERRS_H) */
diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index cc49a2af80..0f76ff23ea 100644
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -555,6 +555,11 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
// about 700 or so requests and starts issuing TCP RSTs to
// new connections. Reuse the DNS lookups for even a few
// seconds and no RSTs.
+ //
+ // -1 stores forever
+ // 0 never stores
+ // any other positive number specifies seconds
+ // supposedly curl 7.62.0 can use TTL by default, otherwise default is 60 seconds
check_curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout);
if (gpolicy.mUseLLProxy)
diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h
index ac518a5de7..d0c37ac195 100644
--- a/indra/llcorehttp/_httpservice.h
+++ b/indra/llcorehttp/_httpservice.h
@@ -31,7 +31,7 @@
#include <vector>
#include "linden_common.h"
-#include "llapr.h"
+#include "llatomic.h"
#include "httpcommon.h"
#include "httprequest.h"
#include "_httppolicyglobal.h"
diff --git a/indra/llcorehttp/_refcounted.h b/indra/llcorehttp/_refcounted.h
index 7f713f2298..5cc8914395 100644
--- a/indra/llcorehttp/_refcounted.h
+++ b/indra/llcorehttp/_refcounted.h
@@ -34,7 +34,7 @@
#include <boost/thread.hpp>
#include <boost/intrusive_ptr.hpp>
-#include "llapr.h"
+#include "llatomic.h"
namespace LLCoreInt
diff --git a/indra/llcorehttp/_thread.h b/indra/llcorehttp/_thread.h
index e058d660e5..22b7750bad 100644
--- a/indra/llcorehttp/_thread.h
+++ b/indra/llcorehttp/_thread.h
@@ -33,6 +33,7 @@
#include <boost/function.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include "apr.h" // thread-related functions
#include "_refcounted.h"
namespace LLCoreInt
diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp
index 1829062af6..7c93c54cdf 100644
--- a/indra/llcorehttp/httpcommon.cpp
+++ b/indra/llcorehttp/httpcommon.cpp
@@ -333,7 +333,7 @@ LLMutex *getCurlMutex()
if (!sHandleMutexp)
{
- sHandleMutexp = new LLMutex(NULL);
+ sHandleMutexp = new LLMutex();
}
return sHandleMutexp;
@@ -389,7 +389,7 @@ void initialize()
S32 mutex_count = CRYPTO_num_locks();
for (S32 i = 0; i < mutex_count; i++)
{
- sSSLMutex.push_back(LLMutex_ptr(new LLMutex(NULL)));
+ sSSLMutex.push_back(LLMutex_ptr(new LLMutex()));
}
CRYPTO_set_id_callback(&ssl_thread_id);
CRYPTO_set_locking_callback(&ssl_locking_callback);
diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp
index b450f3502e..e65588e48f 100644
--- a/indra/llcorehttp/tests/test_httprequest.hpp
+++ b/indra/llcorehttp/tests/test_httprequest.hpp
@@ -2903,6 +2903,13 @@ void HttpRequestTestObjectType::test<22>()
set_test_name("BUG-2295");
+#if LL_WINDOWS && ADDRESS_SIZE == 64
+ // teamcity win64 builds freeze on this test, if you figure out the cause, please fix it
+ if (getenv("TEAMCITY_PROJECT_NAME"))
+ {
+ skip("BUG-2295 - partial load on W64 causes freeze");
+ }
+#endif
// Handler can be stack-allocated *if* there are no dangling
// references to it after completion of this method.
// Create before memory record as the string copy will bump numbers.
@@ -2921,6 +2928,7 @@ void HttpRequestTestObjectType::test<22>()
// options set
options = HttpOptions::ptr_t(new HttpOptions());
options->setRetries(1); // Partial_File is retryable and can timeout in here
+ options->setDNSCacheTimeout(30);
// Get singletons created
HttpRequest::createService();
@@ -3091,7 +3099,11 @@ void HttpRequestTestObjectType::test<23>()
set_test_name("HttpRequest GET 503s with 'Retry-After'");
#if LL_WINDOWS && ADDRESS_SIZE == 64
- skip("llcorehttp 503-with-retry test hangs on Windows 64");
+ // teamcity win64 builds freeze on this test, if you figure out the cause, please fix it
+ if (getenv("TEAMCITY_PROJECT_NAME"))
+ {
+ skip("llcorehttp 503-with-retry test hangs on Windows 64");
+ }
#endif
// This tests mainly that the code doesn't fall over if
diff --git a/indra/llcrashlogger/llcrashlock.cpp b/indra/llcrashlogger/llcrashlock.cpp
index 77abfbcf0f..18d164abde 100644
--- a/indra/llcrashlogger/llcrashlock.cpp
+++ b/indra/llcrashlogger/llcrashlock.cpp
@@ -27,6 +27,7 @@
#include "linden_common.h"
+#include "llapr.h" // thread-related functions
#include "llcrashlock.h"
#include "lldir.h"
#include "llsd.h"
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index 1a4dd2ca99..680fbf548f 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -594,7 +594,7 @@ void LLImage::initClass(bool use_new_byte_range, S32 minimal_reverse_byte_range_
{
sUseNewByteRange = use_new_byte_range;
sMinimalReverseByteRangePercent = minimal_reverse_byte_range_percent;
- sMutex = new LLMutex(NULL);
+ sMutex = new LLMutex();
}
//static
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 4875fe7001..5f42fba866 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -35,7 +35,7 @@
LLImageDecodeThread::LLImageDecodeThread(bool threaded)
: LLQueuedThread("imagedecode", threaded)
{
- mCreationMutex = new LLMutex(getAPRPool());
+ mCreationMutex = new LLMutex();
}
//virtual
diff --git a/indra/llimagej2coj/CMakeLists.txt b/indra/llimagej2coj/CMakeLists.txt
index 97d22cf86a..c9423d50dd 100644
--- a/indra/llimagej2coj/CMakeLists.txt
+++ b/indra/llimagej2coj/CMakeLists.txt
@@ -29,7 +29,9 @@ set_source_files_properties(${llimagej2coj_HEADER_FILES}
list(APPEND llimagej2coj_SOURCE_FILES ${llimagej2coj_HEADER_FILES})
add_library (llimagej2coj ${llimagej2coj_SOURCE_FILES})
+
target_link_libraries(
llimagej2coj
${OPENJPEG_LIBRARIES}
)
+
diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index 3b8f08e0c6..89cdb1c6b9 100644
--- a/indra/llmath/llvolumemgr.cpp
+++ b/indra/llmath/llvolumemgr.cpp
@@ -48,7 +48,7 @@ LLVolumeMgr::LLVolumeMgr()
{
// the LLMutex magic interferes with easy unit testing,
// so you now must manually call useMutex() to use it
- //mDataMutex = new LLMutex(gAPRPoolp);
+ //mDataMutex = new LLMutex();
}
LLVolumeMgr::~LLVolumeMgr()
@@ -214,7 +214,7 @@ void LLVolumeMgr::useMutex()
{
if (!mDataMutex)
{
- mDataMutex = new LLMutex(gAPRPoolp);
+ mDataMutex = new LLMutex();
}
}
diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp
index d07d9980c3..1a0eceba0f 100644
--- a/indra/llmessage/llbuffer.cpp
+++ b/indra/llmessage/llbuffer.cpp
@@ -265,7 +265,7 @@ void LLBufferArray::setThreaded(bool threaded)
{
if(!mMutexp)
{
- mMutexp = new LLMutex(NULL);
+ mMutexp = new LLMutex();
}
}
else
diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp
index 537efa69d8..5730a36267 100644
--- a/indra/llmessage/llproxy.cpp
+++ b/indra/llmessage/llproxy.cpp
@@ -48,7 +48,7 @@ static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP
LLProxy::LLProxy():
mHTTPProxyEnabled(false),
- mProxyMutex(NULL),
+ mProxyMutex(),
mUDPProxy(),
mTCPProxy(),
mHTTPProxy(),
diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h
index 688dff7c83..87891901ad 100644
--- a/indra/llmessage/llproxy.h
+++ b/indra/llmessage/llproxy.h
@@ -298,7 +298,7 @@ private:
private:
// Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly.
// Instead use enableHTTPProxy() and disableHTTPProxy() instead.
- mutable LLAtomic32<bool> mHTTPProxyEnabled;
+ mutable LLAtomicBool mHTTPProxyEnabled;
// Mutex to protect shared members in non-main thread calls to applyProxySettings().
mutable LLMutex mProxyMutex;
diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp
index 506ccc98a4..a2524e9804 100644
--- a/indra/llmessage/llpumpio.cpp
+++ b/indra/llmessage/llpumpio.cpp
@@ -54,11 +54,7 @@
// constants for poll timeout. if we are threading, we want to have a
// longer poll timeout.
-#if LL_THREADS_APR
-static const S32 DEFAULT_POLL_TIMEOUT = 1000;
-#else
static const S32 DEFAULT_POLL_TIMEOUT = 0;
-#endif
// The default (and fallback) expiration time for chains
const F32 DEFAULT_CHAIN_EXPIRY_SECS = 30.0f;
@@ -169,8 +165,6 @@ LLPumpIO::LLPumpIO(apr_pool_t* pool) :
mPool(NULL),
mCurrentPool(NULL),
mCurrentPoolReallocCount(0),
- mChainsMutex(NULL),
- mCallbackMutex(NULL),
mCurrentChain(mRunningChains.end())
{
mCurrentChain = mRunningChains.end();
@@ -194,9 +188,6 @@ bool LLPumpIO::addChain(const chain_t& chain, F32 timeout, bool has_curl_request
{
if(chain.empty()) return false;
-#if LL_THREADS_APR
- LLScopedLock lock(mChainsMutex);
-#endif
LLChainInfo info;
info.mHasCurlRequest = has_curl_request;
info.setTimeoutSeconds(timeout);
@@ -234,9 +225,6 @@ bool LLPumpIO::addChain(
if(!data) return false;
if(links.empty()) return false;
-#if LL_THREADS_APR
- LLScopedLock lock(mChainsMutex);
-#endif
#if LL_DEBUG_PIPE_TYPE_IN_PUMP
LL_DEBUGS() << "LLPumpIO::addChain() " << links[0].mPipe << " '"
<< typeid(*(links[0].mPipe)).name() << "'" << LL_ENDL;
@@ -391,9 +379,6 @@ void LLPumpIO::clearLock(S32 key)
// therefore won't be treading into deleted memory. I think we can
// also clear the lock on the chain safely since the pump only
// reads that value.
-#if LL_THREADS_APR
- LLScopedLock lock(mChainsMutex);
-#endif
mClearLocks.insert(key);
}
@@ -457,9 +442,6 @@ void LLPumpIO::pump(const S32& poll_timeout)
PUMP_DEBUG;
if(true)
{
-#if LL_THREADS_APR
- LLScopedLock lock(mChainsMutex);
-#endif
// bail if this pump is paused.
if(PAUSING == mState)
{
@@ -724,25 +706,10 @@ void LLPumpIO::pump(const S32& poll_timeout)
END_PUMP_DEBUG;
}
-//bool LLPumpIO::respond(const chain_t& pipes)
-//{
-//#if LL_THREADS_APR
-// LLScopedLock lock(mCallbackMutex);
-//#endif
-// LLChainInfo info;
-// links_t links;
-//
-// mPendingCallbacks.push_back(info);
-// return true;
-//}
-
bool LLPumpIO::respond(LLIOPipe* pipe)
{
if(NULL == pipe) return false;
-#if LL_THREADS_APR
- LLScopedLock lock(mCallbackMutex);
-#endif
LLChainInfo info;
LLLinkInfo link;
link.mPipe = pipe;
@@ -761,10 +728,6 @@ bool LLPumpIO::respond(
if(!data) return false;
if(links.empty()) return false;
-#if LL_THREADS_APR
- LLScopedLock lock(mCallbackMutex);
-#endif
-
// Add the callback response
LLChainInfo info;
info.mChainLinks = links;
@@ -781,9 +744,6 @@ void LLPumpIO::callback()
//LL_INFOS() << "LLPumpIO::callback()" << LL_ENDL;
if(true)
{
-#if LL_THREADS_APR
- LLScopedLock lock(mCallbackMutex);
-#endif
std::copy(
mPendingCallbacks.begin(),
mPendingCallbacks.end(),
@@ -809,9 +769,6 @@ void LLPumpIO::callback()
void LLPumpIO::control(LLPumpIO::EControl op)
{
-#if LL_THREADS_APR
- LLScopedLock lock(mChainsMutex);
-#endif
switch(op)
{
case PAUSE:
@@ -829,22 +786,11 @@ void LLPumpIO::control(LLPumpIO::EControl op)
void LLPumpIO::initialize(apr_pool_t* pool)
{
if(!pool) return;
-#if LL_THREADS_APR
- // SJB: Windows defaults to NESTED and OSX defaults to UNNESTED, so use UNNESTED explicitly.
- apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, pool);
- apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, pool);
-#endif
mPool = pool;
}
void LLPumpIO::cleanup()
{
-#if LL_THREADS_APR
- if(mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
- if(mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
-#endif
- mChainsMutex = NULL;
- mCallbackMutex = NULL;
if(mPollset)
{
// LL_DEBUGS() << "cleaning up pollset" << LL_ENDL;
diff --git a/indra/llmessage/llpumpio.h b/indra/llmessage/llpumpio.h
index d2c5d37571..b9eabee710 100644
--- a/indra/llmessage/llpumpio.h
+++ b/indra/llmessage/llpumpio.h
@@ -40,9 +40,6 @@
#include "lliopipe.h"
#include "llrun.h"
-// Define this to enable use with the APR thread library.
-//#define LL_THREADS_APR 1
-
// some simple constants to help with timeouts
extern const F32 DEFAULT_CHAIN_EXPIRY_SECS;
extern const F32 SHORT_CHAIN_EXPIRY_SECS;
@@ -393,14 +390,6 @@ protected:
apr_pool_t* mCurrentPool;
S32 mCurrentPoolReallocCount;
-#if LL_THREADS_APR
- apr_thread_mutex_t* mChainsMutex;
- apr_thread_mutex_t* mCallbackMutex;
-#else
- int* mChainsMutex;
- int* mCallbackMutex;
-#endif
-
protected:
void initialize(apr_pool_t* pool);
void cleanup();
diff --git a/indra/llmessage/tests/commtest.h b/indra/llmessage/tests/commtest.h
index 7c8f27bbd2..0359eba803 100644
--- a/indra/llmessage/tests/commtest.h
+++ b/indra/llmessage/tests/commtest.h
@@ -34,6 +34,7 @@
#include "llsd.h"
#include "llhost.h"
#include "llexception.h"
+#include "llstring.h"
#include "stringize.h"
#include <map>
#include <string>
@@ -46,12 +47,7 @@ struct CommtestError: public LLException
static bool query_verbose()
{
- const char* cbose = getenv("INTEGRATION_TEST_VERBOSE");
- if (! cbose)
- {
- cbose = "1";
- }
- std::string strbose(cbose);
+ std::string strbose(LLStringUtil::getenv("INTEGRATION_TEST_VERBOSE", "1"));
return (! (strbose == "0" || strbose == "off" ||
strbose == "false" || strbose == "quiet"));
}
diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp
index 9356a14f1f..78faa66a0d 100644
--- a/indra/llmessage/tests/llhttpclient_test.cpp
+++ b/indra/llmessage/tests/llhttpclient_test.cpp
@@ -41,6 +41,7 @@
#include "llpumpio.h"
#include "lliosocket.h"
+#include "llstring.h"
#include "stringize.h"
#include "llcleanup.h"
@@ -50,13 +51,13 @@ namespace tut
{
public:
HTTPClientTestData():
- PORT(getenv("PORT")),
+ PORT(LLStringUtil::getenv("PORT")),
// Turning NULL PORT into empty string doesn't make things work;
// that's just to keep this initializer from blowing up. We test
// PORT separately in the constructor body.
- local_server(STRINGIZE("http://127.0.0.1:" << (PORT? PORT : "") << "/"))
+ local_server(STRINGIZE("http://127.0.0.1:" << PORT << "/"))
{
- ensure("Set environment variable PORT to local test server port", PORT);
+ ensure("Set environment variable PORT to local test server port", !PORT.empty());
apr_pool_create(&mPool, NULL);
LLCurl::initClass(false);
mClientPump = new LLPumpIO(mPool);
@@ -87,7 +88,7 @@ namespace tut
}
}
- const char* const PORT;
+ const std::string PORT;
const std::string local_server;
private:
diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp
index 9468696507..9766e1bfed 100644
--- a/indra/llplugin/llpluginmessagepipe.cpp
+++ b/indra/llplugin/llpluginmessagepipe.cpp
@@ -92,8 +92,8 @@ void LLPluginMessagePipeOwner::killMessagePipe(void)
}
LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket):
- mInputMutex(gAPRPoolp),
- mOutputMutex(gAPRPoolp),
+ mInputMutex(),
+ mOutputMutex(),
mOutputStartIndex(0),
mOwner(owner),
mSocket(socket)
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index 0a8e58ac90..eb6cb1b503 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -80,11 +80,11 @@ protected:
};
LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
- mIncomingQueueMutex(gAPRPoolp)
+ mIncomingQueueMutex()
{
if(!sInstancesMutex)
{
- sInstancesMutex = new LLMutex(gAPRPoolp);
+ sInstancesMutex = new LLMutex();
}
mOwner = owner;
diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt
index 0e5e835777..33520ad64c 100644
--- a/indra/llplugin/slplugin/CMakeLists.txt
+++ b/indra/llplugin/slplugin/CMakeLists.txt
@@ -48,7 +48,7 @@ add_executable(SLPlugin
WIN32
MACOSX_BUNDLE
${SLPlugin_SOURCE_FILES}
-)
+ )
if (WINDOWS)
set_target_properties(SLPlugin
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index cf3288489a..51fa2f8079 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -154,7 +154,6 @@ public:
void ClearFacesAndMaterials() { mVolumeFaces.clear(); mMaterialList.clear(); }
std::string getName() const;
- std::string getMetric() const {return mMetric;}
EModelStatus getStatus() const {return mStatus;}
static std::string getStatusString(U32 status) ;
@@ -260,8 +259,6 @@ public:
std::string mRequestedLabel; // name requested in UI, if any.
std::string mLabel; // name computed from dae.
- std::string mMetric; // user-supplied metric data for upload
-
LLVector3 mNormalizedScale;
LLVector3 mNormalizedTranslation;
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index c69c059880..27d1bee9bd 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -1580,7 +1580,7 @@ bool LLPrimitive::getTESTAxes(const U8 face, U32* s_axis, U32* t_axis)
*s_axis = VY; *t_axis = VZ;
return true;
}
- else if (face == 5)
+ else if (face >= 5)
{
*s_axis = VX; *t_axis = VY;
return true;
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index cf0a117567..8cd18c5fa1 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -40,10 +40,17 @@
#include "v4color.h"
#include "lltexture.h"
#include "lldir.h"
+#include "llstring.h"
// Third party library includes
#include <boost/tokenizer.hpp>
+#if LL_WINDOWS
+#include <Shlobj.h>
+#include <Knownfolders.h>
+#include <Objbase.h>
+#endif // LL_WINDOWS
+
const S32 BOLD_OFFSET = 1;
// static class members
@@ -1063,33 +1070,33 @@ LLFontGL* LLFontGL::getFontDefault()
// static
std::string LLFontGL::getFontPathSystem()
{
- std::string system_path;
-
- // Try to figure out where the system's font files are stored.
- char *system_root = NULL;
-#if LL_WINDOWS
- system_root = getenv("SystemRoot"); /* Flawfinder: ignore */
- if (!system_root)
- {
- LL_WARNS() << "SystemRoot not found, attempting to load fonts from default path." << LL_ENDL;
- }
+#if LL_DARWIN
+ // HACK for Mac OS X
+ return "/System/Library/Fonts/";
+
+#elif LL_WINDOWS
+ auto system_root = LLStringUtil::getenv("SystemRoot");
+ if (! system_root.empty())
+ {
+ std::string fontpath(gDirUtilp->add(system_root, "fonts") + gDirUtilp->getDirDelimiter());
+ LL_INFOS() << "from SystemRoot: " << fontpath << LL_ENDL;
+ return fontpath;
+ }
+
+ wchar_t *pwstr = NULL;
+ HRESULT okay = SHGetKnownFolderPath(FOLDERID_Fonts, 0, NULL, &pwstr);
+ if (SUCCEEDED(okay) && pwstr)
+ {
+ std::string fontpath(ll_convert_wide_to_string(pwstr));
+ // SHGetKnownFolderPath() contract requires us to free pwstr
+ CoTaskMemFree(pwstr);
+ LL_INFOS() << "from SHGetKnownFolderPath(): " << fontpath << LL_ENDL;
+ return fontpath;
+ }
#endif
- if (system_root)
- {
- system_path = llformat("%s/fonts/", system_root);
- }
- else
- {
-#if LL_WINDOWS
- // HACK for windows 98/Me
- system_path = "/WINDOWS/FONTS/";
-#elif LL_DARWIN
- // HACK for Mac OS X
- system_path = "/System/Library/Fonts/";
-#endif
- }
- return system_path;
+ LL_WARNS() << "Could not determine system fonts path" << LL_ENDL;
+ return {};
}
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 8054eb3619..e44f57fa9f 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -200,6 +200,7 @@ set(llui_HEADER_FILES
llresizehandle.h
llresmgr.h
llrngwriter.h
+ llsearchablecontrol.h
llsearcheditor.h
llscrollbar.h
llscrollcontainer.h
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 510a2537b9..6b7a8a8b86 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -769,6 +769,10 @@ void LLButton::draw()
}
}
+ // Highlight if needed
+ if( ll::ui::SearchableControl::getHighlighted() )
+ label_color = ll::ui::SearchableControl::getHighlightColor();
+
// Unselected label assignments
LLWString label = getCurrentLabel();
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 7b4719866d..7629ed1fea 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -62,6 +62,7 @@ class LLUICtrlFactory;
class LLButton
: public LLUICtrl, public LLBadgeOwner
+, public ll::ui::SearchableControl
{
public:
struct Params
@@ -380,6 +381,12 @@ protected:
LLFlashTimer * mFlashingTimer;
bool mForceFlashing; // Stick flashing color even if button is pressed
bool mHandleRightMouse;
+
+protected:
+ virtual std::string _getSearchText() const
+ {
+ return getLabelUnselected() + getToolTip();
+ }
};
// Build time optimization, generate once in .cpp file
diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h
index 5ce45b2135..07ae9c3b18 100644
--- a/indra/llui/llcheckboxctrl.h
+++ b/indra/llui/llcheckboxctrl.h
@@ -47,6 +47,7 @@ class LLViewBorder;
class LLCheckBoxCtrl
: public LLUICtrl
+, public ll::ui::SearchableControl
{
public:
struct Params
@@ -92,6 +93,8 @@ public:
// LLCheckBoxCtrl interface
virtual BOOL toggle() { return mButton->toggleState(); } // returns new state
+ void setBtnFocus() { mButton->setFocus(TRUE); }
+
void setEnabledColor( const LLColor4 &color ) { mTextEnabledColor = color; }
void setDisabledColor( const LLColor4 &color ) { mTextDisabledColor = color; }
@@ -107,6 +110,18 @@ public:
virtual void resetDirty(); // Clear dirty state
protected:
+ virtual std::string _getSearchText() const
+ {
+ return getLabel() + getToolTip();
+ }
+
+ virtual void onSetHighlight() const // When highlight, really do highlight the label
+ {
+ if( mLabel )
+ mLabel->ll::ui::SearchableControl::setHighlighted( ll::ui::SearchableControl::getHighlighted() );
+ }
+
+protected:
// note: value is stored in toggle state of button
LLButton* mButton;
LLTextBox* mLabel;
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 00a933a0bb..b2ad38bddf 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -243,7 +243,14 @@ LLScrollListItem* LLComboBox::add(const std::string& name, EAddPosition pos, BOO
item->setEnabled(enabled);
if (!mAllowTextEntry && mLabel.empty())
{
- selectFirstItem();
+ if (mControlVariable)
+ {
+ setValue(mControlVariable->getValue()); // selects the appropriate item
+ }
+ else
+ {
+ selectFirstItem();
+ }
}
return item;
}
@@ -255,7 +262,14 @@ LLScrollListItem* LLComboBox::add(const std::string& name, const LLUUID& id, EAd
item->setEnabled(enabled);
if (!mAllowTextEntry && mLabel.empty())
{
- selectFirstItem();
+ if (mControlVariable)
+ {
+ setValue(mControlVariable->getValue()); // selects the appropriate item
+ }
+ else
+ {
+ selectFirstItem();
+ }
}
return item;
}
@@ -268,7 +282,14 @@ LLScrollListItem* LLComboBox::add(const std::string& name, void* userdata, EAddP
item->setUserdata( userdata );
if (!mAllowTextEntry && mLabel.empty())
{
- selectFirstItem();
+ if (mControlVariable)
+ {
+ setValue(mControlVariable->getValue()); // selects the appropriate item
+ }
+ else
+ {
+ selectFirstItem();
+ }
}
return item;
}
@@ -280,7 +301,14 @@ LLScrollListItem* LLComboBox::add(const std::string& name, LLSD value, EAddPosit
item->setEnabled(enabled);
if (!mAllowTextEntry && mLabel.empty())
{
- selectFirstItem();
+ if (mControlVariable)
+ {
+ setValue(mControlVariable->getValue()); // selects the appropriate item
+ }
+ else
+ {
+ selectFirstItem();
+ }
}
return item;
}
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 69246a2f57..b1ba725c2f 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -251,8 +251,14 @@ void LLLayoutStack::draw()
// always clip to stack itself
LLLocalClipRect clip(getLocalRect());
- BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
+ for (LLLayoutPanel* panelp : mPanels)
{
+ if ((!panelp->getVisible() || panelp->mCollapsed)
+ && (panelp->mVisibleAmt < 0.001f || !mAnimate))
+ {
+ // essentially invisible
+ continue;
+ }
// clip to layout rectangle, not bounding rectangle
LLRect clip_rect = panelp->getRect();
// scale clipping rectangle by visible amount
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 0d42f726fa..92543b952e 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -504,6 +504,10 @@ void LLMenuItemGL::draw( void )
color = mDisabledColor.get();
}
+ // Highlight if needed
+ if( ll::ui::SearchableControl::getHighlighted() )
+ color = ll::ui::SearchableControl::getHighlightColor();
+
// Draw the text on top.
if (mBriefItem)
{
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 69f7d21513..78f688642e 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -48,7 +48,7 @@ extern S32 MENU_BAR_WIDTH;
// The LLMenuItemGL represents a single menu item in a menu.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLMenuItemGL : public LLUICtrl
+class LLMenuItemGL: public LLUICtrl, public ll::ui::SearchableControl
{
public:
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
@@ -175,7 +175,12 @@ protected:
// This function appends the character string representation of
// the current accelerator key and mask to the provided string.
void appendAcceleratorString( std::string& st ) const;
-
+
+ virtual std::string _getSearchText() const
+ {
+ return mLabel.getString();
+ }
+
protected:
KEY mAcceleratorKey;
MASK mAcceleratorMask;
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index b6a32a0e78..be26416cbb 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -90,9 +90,12 @@ void LLNotificationsListener::requestAdd(const LLSD& event_data) const
{
if(event_data.has("reply"))
{
+ LLSD payload(event_data["payload"]);
+ // copy reqid, if provided, to link response with request
+ payload["reqid"] = event_data["reqid"];
mNotifications.add(event_data["name"],
event_data["substitutions"],
- event_data["payload"],
+ payload,
boost::bind(&LLNotificationsListener::NotificationResponder,
this,
event_data["reply"].asString(),
@@ -112,10 +115,12 @@ void LLNotificationsListener::NotificationResponder(const std::string& reply_pum
const LLSD& notification,
const LLSD& response) const
{
- LLSD reponse_event;
- reponse_event["notification"] = notification;
- reponse_event["response"] = response;
- LLEventPumps::getInstance()->obtain(reply_pump).post(reponse_event);
+ LLSD response_event;
+ response_event["notification"] = notification;
+ response_event["response"] = response;
+ // surface reqid at top level of response for request/response protocol
+ response_event["reqid"] = notification["payload"]["reqid"];
+ LLEventPumps::getInstance()->obtain(reply_pump).post(response_event);
}
void LLNotificationsListener::listChannels(const LLSD& params) const
diff --git a/indra/llui/llsearchablecontrol.h b/indra/llui/llsearchablecontrol.h
new file mode 100644
index 0000000000..f7f1ffa0a5
--- /dev/null
+++ b/indra/llui/llsearchablecontrol.h
@@ -0,0 +1,71 @@
+/**
+* @file llsearchablecontrol.h
+*
+* $LicenseInfo:firstyear=2019&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2019, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#ifndef LL_SEARCHABLE_CONTROL_H
+#define LL_SEARCHABLE_CONTROL_H
+
+#include "lluicolortable.h"
+#include "lluicolor.h"
+
+namespace ll
+{
+ namespace ui
+ {
+ class SearchableControl
+ {
+ mutable bool mIsHighlighed;
+ public:
+ SearchableControl()
+ : mIsHighlighed( false )
+ { }
+ virtual ~SearchableControl()
+ { }
+
+ LLColor4 getHighlightColor( ) const
+ {
+ static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red);
+ return highlight_color.get();
+ }
+
+ void setHighlighted( bool aVal ) const
+ {
+ mIsHighlighed = aVal;
+ onSetHighlight( );
+ }
+ bool getHighlighted( ) const
+ { return mIsHighlighed; }
+
+ std::string getSearchText() const
+ { return _getSearchText(); }
+ protected:
+ virtual std::string _getSearchText() const = 0;
+ virtual void onSetHighlight( ) const
+ { }
+ };
+ }
+}
+
+
+#endif
diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h
index 67cca9ef04..2bb8668b90 100644
--- a/indra/llui/llsliderctrl.h
+++ b/indra/llui/llsliderctrl.h
@@ -35,7 +35,7 @@
#include "lllineeditor.h"
-class LLSliderCtrl : public LLF32UICtrl
+class LLSliderCtrl: public LLF32UICtrl, public ll::ui::SearchableControl
{
public:
struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params>
@@ -131,6 +131,19 @@ public:
static void onEditorGainFocus(LLFocusableElement* caller, void *userdata);
static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
+protected:
+ virtual std::string _getSearchText() const
+ {
+ std::string strLabel;
+ if( mLabelBox )
+ strLabel = mLabelBox->getLabel();
+ return strLabel + getToolTip();
+ }
+ virtual void onSetHighlight() const // When highlight, really do highlight the label
+ {
+ if( mLabelBox )
+ mLabelBox->ll::ui::SearchableControl::setHighlighted( ll::ui::SearchableControl::getHighlighted() );
+ }
private:
void updateText();
void reportInvalidData();
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 1b2f09cff5..6521b883f8 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -76,7 +76,8 @@ public:
mButton(b),
mOldState(FALSE),
mPlaceholderText(placeholder),
- mPadding(0)
+ mPadding(0),
+ mVisible(true)
{}
LLTabContainer* mTabContainer;
@@ -85,6 +86,8 @@ public:
BOOL mOldState;
LLTextBox* mPlaceholderText;
S32 mPadding;
+
+ mutable bool mVisible;
};
//----------------------------------------------------------------------------
@@ -398,7 +401,10 @@ void LLTabContainer::draw()
{
break;
}
- target_pixel_scroll += (*iter)->mButton->getRect().getWidth();
+
+ if( (*iter)->mVisible )
+ target_pixel_scroll += (*iter)->mButton->getRect().getWidth();
+
cur_scroll_pos--;
}
@@ -467,6 +473,12 @@ void LLTabContainer::draw()
{
LLTabTuple* tuple = *iter;
+ if( !tuple->mVisible )
+ {
+ tuple->mButton->setVisible( false );
+ continue;
+ }
+
tuple->mButton->translate( left ? left - tuple->mButton->getRect().mLeft : 0,
top ? top - tuple->mButton->getRect().mTop : 0 );
if (top) top -= BTN_HEIGHT + tabcntrv_pad;
@@ -724,11 +736,11 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, MASK mask)
{
for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
{
- LLTabTuple* tuple = *iter;
- tuple->mButton->setVisible( TRUE );
- S32 local_x = x - tuple->mButton->getRect().mLeft;
- S32 local_y = y - tuple->mButton->getRect().mBottom;
- handled = tuple->mButton->handleToolTip( local_x, local_y, mask);
+ LLButton* tab_button = (*iter)->mButton;
+ if (!tab_button->getVisible()) continue;
+ S32 local_x = x - tab_button->getRect().mLeft;
+ S32 local_y = y - tab_button->getRect().mBottom;
+ handled = tab_button->handleToolTip(local_x, local_y, mask);
if( handled )
{
break;
@@ -1505,7 +1517,7 @@ BOOL LLTabContainer::setTab(S32 which)
}
BOOL is_visible = FALSE;
- if (selected_tuple->mButton->getEnabled())
+ if( selected_tuple->mButton->getEnabled() && selected_tuple->mVisible )
{
setCurrentPanelIndex(which);
@@ -2121,3 +2133,35 @@ S32 LLTabContainer::getTotalTabWidth() const
{
return mTotalTabWidth;
}
+
+void LLTabContainer::setTabVisibility( LLPanel const *aPanel, bool aVisible )
+{
+ for( tuple_list_t::const_iterator itr = mTabList.begin(); itr != mTabList.end(); ++itr )
+ {
+ LLTabTuple const *pTT = *itr;
+ if( pTT->mTabPanel == aPanel )
+ {
+ pTT->mVisible = aVisible;
+ break;
+ }
+ }
+
+ bool foundTab( false );
+ for( tuple_list_t::const_iterator itr = mTabList.begin(); itr != mTabList.end(); ++itr )
+ {
+ LLTabTuple const *pTT = *itr;
+ if( pTT->mVisible )
+ {
+ this->selectTab( itr - mTabList.begin() );
+ foundTab = true;
+ break;
+ }
+ }
+
+ if( foundTab )
+ this->setVisible( TRUE );
+ else
+ this->setVisible( FALSE );
+
+ updateMaxScrollPos();
+}
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index 4a5f08f5d3..6bf963313c 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -216,6 +216,8 @@ public:
S32 getMinTabWidth() const { return mMinTabWidth; }
S32 getMaxTabWidth() const { return mMaxTabWidth; }
+ void setTabVisibility( LLPanel const *aPanel, bool );
+
void startDragAndDropDelayTimer() { mDragAndDropDelayTimer.start(); }
void onTabBtn( const LLSD& data, LLPanel* panel );
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index c570285856..a23741b6dd 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1222,6 +1222,17 @@ void LLTextBase::draw()
gl_rect_2d(text_rect, bg_color % alpha, TRUE);
}
+ // Draw highlighted if needed
+ if( ll::ui::SearchableControl::getHighlighted() )
+ {
+ LLColor4 bg_color = ll::ui::SearchableControl::getHighlightColor();
+ LLRect bg_rect = mVisibleTextRect;
+ if( mScroller )
+ bg_rect.intersectWith( text_rect );
+
+ gl_rect_2d( text_rect, bg_color, TRUE );
+ }
+
bool should_clip = mClip || mScroller != NULL;
{ LLLocalClipRect clip(text_rect, should_clip);
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 5fdde445ef..9831c35858 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -275,7 +275,8 @@ typedef LLPointer<LLTextSegment> LLTextSegmentPtr;
class LLTextBase
: public LLUICtrl,
protected LLEditMenuHandler,
- public LLSpellCheckMenuHandler
+ public LLSpellCheckMenuHandler,
+ public ll::ui::SearchableControl
{
public:
friend class LLTextSegment;
@@ -617,6 +618,11 @@ protected:
void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false);
S32 normalizeUri(std::string& uri);
+protected:
+ virtual std::string _getSearchText() const
+ {
+ return mLabel.getString() + getToolTip();
+ }
protected:
// text segmentation and flow
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 134b76c720..137167db2a 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -732,14 +732,30 @@ BOOL LLTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
setFocus(TRUE);
}
+
+ bool show_menu = false;
+
// Prefer editor menu if it has selection. See EXT-6806.
- if (hasSelection() || !LLTextBase::handleRightMouseDown(x, y, mask))
+ if (hasSelection())
{
- if(getShowContextMenu())
+ S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE);
+ if (click_pos > mSelectionStart && click_pos < mSelectionEnd)
{
- showContextMenu(x, y);
+ show_menu = true;
}
}
+
+ // Let segments handle the click, if nothing does, show editor menu
+ if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask))
+ {
+ show_menu = true;
+ }
+
+ if (show_menu && getShowContextMenu())
+ {
+ showContextMenu(x, y);
+ }
+
return TRUE;
}
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 550bee5c70..63baed6793 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -37,6 +37,7 @@
#include "llinitparam.h"
#include "llview.h"
#include "llviewmodel.h" // *TODO move dependency to .cpp file
+#include "llsearchablecontrol.h"
const BOOL TAKE_FOCUS_YES = TRUE;
const BOOL TAKE_FOCUS_NO = FALSE;
diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp
index 2069888774..18836e54b0 100644
--- a/indra/llvfs/lldir.cpp
+++ b/indra/llvfs/lldir.cpp
@@ -42,6 +42,7 @@
#include "lldiriterator.h"
#include "stringize.h"
+#include "llstring.h"
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/range/begin.hpp>
@@ -317,9 +318,9 @@ const std::string& LLDir::getChatLogsDir() const
void LLDir::setDumpDir( const std::string& path )
{
LLDir::sDumpDir = path;
- if (! sDumpDir.empty() && sDumpDir.rbegin() == mDirDelimiter.rbegin() )
+ if (LLStringUtil::endsWith(sDumpDir, mDirDelimiter))
{
- sDumpDir.erase(sDumpDir.size() -1);
+ sDumpDir.erase(sDumpDir.size() - mDirDelimiter.size());
}
}
diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp
index 2cd06b81f8..80ad05345a 100644
--- a/indra/llvfs/lldir_linux.cpp
+++ b/indra/llvfs/lldir_linux.cpp
@@ -29,6 +29,7 @@
#include "lldir_linux.h"
#include "llerror.h"
#include "llrand.h"
+#include "llstring.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -40,28 +41,24 @@ static std::string getCurrentUserHome(char* fallback)
{
const uid_t uid = getuid();
struct passwd *pw;
- char *result_cstr = fallback;
-
+
pw = getpwuid(uid);
if ((pw != NULL) && (pw->pw_dir != NULL))
{
- result_cstr = (char*) pw->pw_dir;
+ return pw->pw_dir;
+ }
+
+ LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL;
+ auto home_env = LLStringUtil::getoptenv("HOME");
+ if (home_env)
+ {
+ return *home_env;
}
else
{
- LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL;
- const char *const home_env = getenv("HOME"); /* Flawfinder: ignore */
- if (home_env)
- {
- result_cstr = (char*) home_env;
- }
- else
- {
- LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL;
- }
+ LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL;
+ return fallback;
}
-
- return std::string(result_cstr);
}
@@ -156,18 +153,18 @@ void LLDir_Linux::initAppDirs(const std::string &app_name,
if (!app_read_only_data_dir.empty())
{
mAppRODataDir = app_read_only_data_dir;
- mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins";
+ mSkinBaseDir = add(mAppRODataDir, "skins");
}
mAppName = app_name;
std::string upper_app_name(app_name);
LLStringUtil::toUpper(upper_app_name);
- char* app_home_env = getenv((upper_app_name + "_USER_DIR").c_str()); /* Flawfinder: ignore */
+ auto app_home_env(LLStringUtil::getoptenv(upper_app_name + "_USER_DIR"));
if (app_home_env)
{
// user has specified own userappdir i.e. $SECONDLIFE_USER_DIR
- mOSUserAppDir = app_home_env;
+ mOSUserAppDir = *app_home_env;
}
else
{
diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp
index 79c4362747..87dc1b9795 100644
--- a/indra/llvfs/lldir_mac.cpp
+++ b/indra/llvfs/lldir_mac.cpp
@@ -171,9 +171,9 @@ void LLDir_Mac::initAppDirs(const std::string &app_name,
if (!app_read_only_data_dir.empty())
{
mAppRODataDir = app_read_only_data_dir;
- mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins";
+ mSkinBaseDir = add(mAppRODataDir, "skins");
}
- mCAFile = getExpandedFilename(LL_PATH_EXECUTABLE, "../Resources", "ca-bundle.crt");
+ mCAFile = add(mAppRODataDir, "ca-bundle.crt");
}
std::string LLDir_Mac::getCurPath()
diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp
index d3536a12ee..f18560ff20 100644
--- a/indra/llvfs/lldir_solaris.cpp
+++ b/indra/llvfs/lldir_solaris.cpp
@@ -29,6 +29,7 @@
#include "lldir_solaris.h"
#include "llerror.h"
#include "llrand.h"
+#include "llstring.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -41,30 +42,28 @@
static std::string getCurrentUserHome(char* fallback)
{
+ // fwiw this exactly duplicates getCurrentUserHome() in lldir_linux.cpp...
+ // we should either derive both from LLDir_Posix or just axe Solaris.
const uid_t uid = getuid();
struct passwd *pw;
- char *result_cstr = fallback;
-
+
pw = getpwuid(uid);
if ((pw != NULL) && (pw->pw_dir != NULL))
{
- result_cstr = (char*) pw->pw_dir;
+ return pw->pw_dir;
+ }
+
+ LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL;
+ auto home_env = LLStringUtil::getoptenv("HOME");
+ if (home_env)
+ {
+ return *home_env;
}
else
{
- LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL;
- const char *const home_env = getenv("HOME"); /* Flawfinder: ignore */
- if (home_env)
- {
- result_cstr = (char*) home_env;
- }
- else
- {
- LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL;
- }
+ LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL;
+ return fallback;
}
-
- return std::string(result_cstr);
}
@@ -135,27 +134,15 @@ LLDir_Solaris::LLDir_Solaris()
//NOTE: Why force people to cd into the package directory?
// Look for SECONDLIFE env variable and use it, if set.
- char *dcf = getenv("SECONDLIFE");
- if(dcf != NULL){
- (void)strcpy(path, dcf);
- (void)strcat(path, "/bin"); //NOTE: make sure we point at the bin
- mExecutableDir = strdup(path);
+ auto SECONDLIFE(LLDirUtil::getoptenv("SECONDLIFE"));
+ if(SECONDLIFE){
+ mExecutableDir = add(*SECONDLIFE, "bin"); //NOTE: make sure we point at the bin
}else{
- // plunk a null at last '/' to get exec dir
- char *s = execpath + strlen(execpath) -1;
- while(*s != '/' && s != execpath){
- --s;
- }
-
- if(s != execpath){
- *s = (char)NULL;
-
- mExecutableDir = strdup(execpath);
- LL_INFOS() << "mExecutableDir = [" << mExecutableDir << "]" << LL_ENDL;
- }
+ mExecutableDir = getDirName(execpath);
+ LL_INFOS() << "mExecutableDir = [" << mExecutableDir << "]" << LL_ENDL;
}
-
- mLLPluginDir = mExecutableDir + mDirDelimiter + "llplugin";
+
+ mLLPluginDir = add(mExecutableDir, "llplugin");
// *TODO: don't use /tmp, use $HOME/.secondlife/tmp or something.
mTempDir = "/tmp";
@@ -175,17 +162,18 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name,
if (!app_read_only_data_dir.empty())
{
mAppRODataDir = app_read_only_data_dir;
+ mSkinBaseDir = add(mAppRODataDir, "skins");
}
mAppName = app_name;
std::string upper_app_name(app_name);
LLStringUtil::toUpper(upper_app_name);
- char* app_home_env = getenv((upper_app_name + "_USER_DIR").c_str()); /* Flawfinder: ignore */
+ auto app_home_env(LLStringUtil::getoptenv(upper_app_name + "_USER_DIR"));
if (app_home_env)
{
// user has specified own userappdir i.e. $SECONDLIFE_USER_DIR
- mOSUserAppDir = app_home_env;
+ mOSUserAppDir = *app_home_env;
}
else
{
diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp
index 9836fa28f2..b3b3afb37e 100644
--- a/indra/llvfs/lldir_win32.cpp
+++ b/indra/llvfs/lldir_win32.cpp
@@ -30,7 +30,9 @@
#include "lldir_win32.h"
#include "llerror.h"
-#include "llrand.h" // for gLindenLabRandomNumber
+#include "llstring.h"
+#include "stringize.h"
+#include "llfile.h"
#include <shlobj.h>
#include <fstream>
@@ -43,15 +45,87 @@
#define PACKVERSION(major,minor) MAKELONG(minor,major)
DWORD GetDllVersion(LPCTSTR lpszDllName);
+namespace
+{ // anonymous
+ enum class prst { INIT, OPEN, SKIP } state = prst::INIT;
+ // This is called so early that we can't count on static objects being
+ // properly constructed yet, so declare a pointer instead of an instance.
+ std::ofstream* prelogf = nullptr;
+
+ void prelog(const std::string& message)
+ {
+ boost::optional<std::string> prelog_name;
+
+ switch (state)
+ {
+ case prst::INIT:
+ // assume we failed, until we succeed
+ state = prst::SKIP;
+
+ prelog_name = LLStringUtil::getoptenv("PRELOG");
+ if (! prelog_name)
+ // no PRELOG variable set, carry on
+ return;
+ prelogf = new llofstream(*prelog_name, std::ios_base::app);
+ if (! (prelogf && prelogf->is_open()))
+ // can't complain to anybody; how?
+ return;
+ // got the log file open, cool!
+ state = prst::OPEN;
+ (*prelogf) << "========================================================================"
+ << std::endl;
+ // fall through, don't break
+
+ case prst::OPEN:
+ (*prelogf) << message << std::endl;
+ break;
+
+ case prst::SKIP:
+ // either PRELOG isn't set, or we failed to open that pathname
+ break;
+ }
+ }
+} // anonymous namespace
+
+#define PRELOG(expression) prelog(STRINGIZE(expression))
+
LLDir_Win32::LLDir_Win32()
{
// set this first: used by append() and add() methods
mDirDelimiter = "\\";
+ WCHAR w_str[MAX_PATH];
// Application Data is where user settings go. We rely on $APPDATA being
- // correct; in fact the VMP makes a point of setting it properly, since
- // Windows itself botches the job for non-ASCII usernames (MAINT-8087).
- mOSUserDir = ll_safe_string(getenv("APPDATA"));
+ // correct.
+ auto APPDATA = LLStringUtil::getoptenv("APPDATA");
+ if (APPDATA)
+ {
+ mOSUserDir = *APPDATA;
+ }
+ PRELOG("APPDATA='" << mOSUserDir << "'");
+ // On Windows, we could have received a plain-ASCII pathname in which
+ // non-ASCII characters have been munged to '?', or the pathname could
+ // have been badly encoded and decoded such that we now have garbage
+ // instead of a valid path. Check that mOSUserDir actually exists.
+ if (mOSUserDir.empty() || ! fileExists(mOSUserDir))
+ {
+ PRELOG("APPDATA does not exist");
+ //HRESULT okay = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, w_str);
+ wchar_t *pwstr = NULL;
+ HRESULT okay = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &pwstr);
+ PRELOG("SHGetKnownFolderPath(FOLDERID_RoamingAppData) returned " << okay);
+ if (SUCCEEDED(okay) && pwstr)
+ {
+ // But of course, only update mOSUserDir if SHGetKnownFolderPath() works.
+ mOSUserDir = ll_convert_wide_to_string(pwstr);
+ // Not only that: update our environment so that child processes
+ // will see a reasonable value as well.
+ _wputenv_s(L"APPDATA", pwstr);
+ // SHGetKnownFolderPath() contract requires us to free pwstr
+ CoTaskMemFree(pwstr);
+ PRELOG("mOSUserDir='" << mOSUserDir << "'");
+ }
+ }
// We want cache files to go on the local disk, even if the
// user is on a network with a "roaming profile".
@@ -61,9 +135,34 @@ LLDir_Win32::LLDir_Win32()
//
// We used to store the cache in AppData\Roaming, and the installer
// cleans up that version on upgrade. JC
- mOSCacheDir = ll_safe_string(getenv("LOCALAPPDATA"));
+ auto LOCALAPPDATA = LLStringUtil::getoptenv("LOCALAPPDATA");
+ if (LOCALAPPDATA)
+ {
+ mOSCacheDir = *LOCALAPPDATA;
+ }
+ PRELOG("LOCALAPPDATA='" << mOSCacheDir << "'");
+ // Windows really does not deal well with pathnames containing non-ASCII
+ // characters. See above remarks about APPDATA.
+ if (mOSCacheDir.empty() || ! fileExists(mOSCacheDir))
+ {
+ PRELOG("LOCALAPPDATA does not exist");
+ //HRESULT okay = SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, w_str);
+ wchar_t *pwstr = NULL;
+ HRESULT okay = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &pwstr);
+ PRELOG("SHGetKnownFolderPath(FOLDERID_LocalAppData) returned " << okay);
+ if (SUCCEEDED(okay) && pwstr)
+ {
+ // But of course, only update mOSCacheDir if SHGetKnownFolderPath() works.
+ mOSCacheDir = ll_convert_wide_to_string(pwstr);
+ // Update our environment so that child processes will see a
+ // reasonable value as well.
+ _wputenv_s(L"LOCALAPPDATA", pwstr);
+ // SHGetKnownFolderPath() contract requires us to free pwstr
+ CoTaskMemFree(pwstr);
+ PRELOG("mOSCacheDir='" << mOSCacheDir << "'");
+ }
+ }
- WCHAR w_str[MAX_PATH];
if (GetTempPath(MAX_PATH, w_str))
{
if (wcslen(w_str)) /* Flawfinder: ignore */
diff --git a/indra/llvfs/lllfsthread.h b/indra/llvfs/lllfsthread.h
index cdb5c75946..58f658f7ba 100644
--- a/indra/llvfs/lllfsthread.h
+++ b/indra/llvfs/lllfsthread.h
@@ -32,7 +32,6 @@
#include <map>
#include <set>
-#include "llapr.h"
#include "llpointer.h"
#include "llqueuedthread.h"
diff --git a/indra/llvfs/llpidlock.cpp b/indra/llvfs/llpidlock.cpp
index 6572edead3..f770e93d45 100644
--- a/indra/llvfs/llpidlock.cpp
+++ b/indra/llvfs/llpidlock.cpp
@@ -27,6 +27,7 @@
#include "linden_common.h"
+#include "llapr.h" // thread-related functions
#include "llpidlock.h"
#include "lldir.h"
#include "llsd.h"
diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp
index d5bd1834c2..617056d94d 100644
--- a/indra/llvfs/llvfs.cpp
+++ b/indra/llvfs/llvfs.cpp
@@ -234,7 +234,7 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename
mDataFP(NULL),
mIndexFP(NULL)
{
- mDataMutex = new LLMutex(0);
+ mDataMutex = new LLMutex();
S32 i;
for (i = 0; i < VFSLOCK_COUNT; i++)
diff --git a/indra/llvfs/llvfsthread.h b/indra/llvfs/llvfsthread.h
index 95f3c857c6..7814de4a2d 100644
--- a/indra/llvfs/llvfsthread.h
+++ b/indra/llvfs/llvfsthread.h
@@ -32,8 +32,6 @@
#include <map>
#include <set>
-#include "llapr.h"
-
#include "llqueuedthread.h"
#include "llvfs.h"
diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm
index c8c086d705..8923ea6458 100644
--- a/indra/llwindow/llopenglview-objc.mm
+++ b/indra/llwindow/llopenglview-objc.mm
@@ -322,6 +322,10 @@ attributedStringInfo getSegments(NSAttributedString *str)
- (void) mouseDown:(NSEvent *)theEvent
{
+ NSPoint mPoint = [theEvent locationInWindow];
+ mMousePos[0] = mPoint.x;
+ mMousePos[1] = mPoint.y;
+
// Apparently people still use this?
if ([theEvent modifierFlags] & NSCommandKeyMask &&
!([theEvent modifierFlags] & NSControlKeyMask) &&
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 843294c239..d4afbb15df 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -1429,12 +1429,10 @@ static CursorRef gCursors[UI_CURSOR_COUNT];
static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY)
{
// cursors are in <Application Bundle>/Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif
- std::string fullpath = gDirUtilp->getAppRODataDir();
- fullpath += gDirUtilp->getDirDelimiter();
- fullpath += "cursors_mac";
- fullpath += gDirUtilp->getDirDelimiter();
- fullpath += cursorIDToName(cursorid);
- fullpath += ".tif";
+ std::string fullpath = gDirUtilp->add(
+ gDirUtilp->getAppRODataDir(),
+ "cursors_mac",
+ cursorIDToName(cursorid) + std::string(".tif"));
gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY);
}
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 4ee4a5357c..504c1589b0 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -3275,8 +3275,10 @@ S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 t
break;
}
- // HACK! Doesn't properly handle wide strings!
- int retval_win = MessageBoxA(NULL, text.c_str(), caption.c_str(), uType);
+ int retval_win = MessageBoxW(NULL, // HWND
+ ll_convert_string_to_wide(text).c_str(),
+ ll_convert_string_to_wide(caption).c_str(),
+ uType);
S32 retval;
switch(retval_win)
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index 20ab1a7ad3..ccf4f3ddf5 100644
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -43,6 +43,9 @@
#include "llrect.h"
#include "llxmltree.h"
#include "llsdserialize.h"
+#include "llfile.h"
+#include "lltimer.h"
+#include "lldir.h"
#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
#define CONTROL_ERRS LL_ERRS("ControlErrors")
@@ -92,6 +95,17 @@ template <> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, cons
//this defines the current version of the settings file
const S32 CURRENT_VERSION = 101;
+// If you define the environment variable LL_SETTINGS_PROFILE to any value this will activate
+// the gSavedSettings profiling code. This code tracks the calls to get a saved (debug) setting.
+// When the viewer exits the results are written to the log directory to the file specified
+// by SETTINGS_PROFILE below. Only settings with an average access rate >= 2/second are output.
+typedef std::pair<std::string, U32> settings_pair_t;
+typedef std::vector<settings_pair_t> settings_vec_t;
+LLSD getCount;
+settings_vec_t getCount_v;
+F64 start_time = 0;
+std::string SETTINGS_PROFILE = "settings_profile.log";
+
bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b)
{
bool result = false;
@@ -327,6 +341,11 @@ LLSD LLControlVariable::getSaveValue() const
LLPointer<LLControlVariable> LLControlGroup::getControl(const std::string& name)
{
+ if (mSettingsProfile)
+ {
+ incrCount(name);
+ }
+
ctrl_name_table_t::iterator iter = mNameTable.find(name);
return iter == mNameTable.end() ? LLPointer<LLControlVariable>() : iter->second;
}
@@ -349,8 +368,14 @@ const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32"
};
LLControlGroup::LLControlGroup(const std::string& name)
-: LLInstanceTracker<LLControlGroup, std::string>(name)
+: LLInstanceTracker<LLControlGroup, std::string>(name),
+ mSettingsProfile(false)
{
+
+ if (NULL != getenv("LL_SETTINGS_PROFILE"))
+ {
+ mSettingsProfile = true;
+ }
}
LLControlGroup::~LLControlGroup()
@@ -358,8 +383,66 @@ LLControlGroup::~LLControlGroup()
cleanup();
}
+static bool compareRoutine(settings_pair_t lhs, settings_pair_t rhs)
+{
+ return lhs.second > rhs.second;
+};
+
void LLControlGroup::cleanup()
{
+ if(mSettingsProfile && getCount.size() != 0)
+ {
+ std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE);
+ LLFILE* out = LLFile::fopen(file, "w"); /* Flawfinder: ignore */
+ if(!out)
+ {
+ LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL;
+ }
+ else
+ {
+ F64 end_time = LLTimer::getTotalSeconds();
+ U32 total_seconds = (U32)(end_time - start_time);
+
+ std::string msg = llformat("Runtime (seconds): %d\n\n No. accesses Avg. accesses/sec Name\n", total_seconds);
+ std::ostringstream data_msg;
+
+ data_msg << msg;
+ size_t data_size = data_msg.str().size();
+ if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size)
+ {
+ LL_WARNS("SettingsProfile") << "Failed to write settings profile header" << LL_ENDL;
+ }
+
+ for (LLSD::map_const_iterator iter = getCount.beginMap(); iter != getCount.endMap(); ++iter)
+ {
+ getCount_v.push_back(settings_pair_t(iter->first, iter->second.asInteger()));
+ }
+ sort(getCount_v.begin(), getCount_v.end(), compareRoutine);
+
+ for (settings_vec_t::iterator iter = getCount_v.begin(); iter != getCount_v.end(); ++iter)
+ {
+ U32 access_rate = 0;
+ if (total_seconds != 0)
+ {
+ access_rate = iter->second / total_seconds;
+ }
+ if (access_rate >= 2)
+ {
+ std::ostringstream data_msg;
+ msg = llformat("%13d %7d %s", iter->second, access_rate, iter->first.c_str());
+ data_msg << msg << "\n";
+ size_t data_size = data_msg.str().size();
+ if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size)
+ {
+ LL_WARNS("SettingsProfile") << "Failed to write settings profile" << LL_ENDL;
+ }
+ }
+ }
+ getCount = LLSD::emptyMap();
+ fclose(out);
+ }
+ }
+
mNameTable.clear();
}
@@ -460,6 +543,15 @@ LLControlVariable* LLControlGroup::declareLLSD(const std::string& name, const LL
return declareControl(name, TYPE_LLSD, initial_val, comment, persist);
}
+void LLControlGroup::incrCount(const std::string& name)
+{
+ if (0.0 == start_time)
+ {
+ start_time = LLTimer::getTotalSeconds();
+ }
+ getCount[name] = getCount[name].asInteger() + 1;
+}
+
BOOL LLControlGroup::getBOOL(const std::string& name)
{
return (BOOL)get<bool>(name);
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index 8136a3e88a..de0d366492 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -301,6 +301,9 @@ public:
U32 saveToFile(const std::string& filename, BOOL nondefault_only);
U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true);
void resetToDefaults();
+ void incrCount(const std::string& name);
+
+ bool mSettingsProfile;
};
diff --git a/indra/llxml/tests/llcontrol_test.cpp b/indra/llxml/tests/llcontrol_test.cpp
index 2b691ffbb1..f7e43d6def 100644
--- a/indra/llxml/tests/llcontrol_test.cpp
+++ b/indra/llxml/tests/llcontrol_test.cpp
@@ -27,43 +27,31 @@
#include "linden_common.h"
#include "llsdserialize.h"
+#include "llfile.h"
+#include "stringize.h"
#include "../llcontrol.h"
#include "../test/lltut.h"
+#include <memory>
+#include <vector>
namespace tut
{
-
struct control_group
{
- LLControlGroup* mCG;
+ std::unique_ptr<LLControlGroup> mCG;
std::string mTestConfigDir;
std::string mTestConfigFile;
+ std::vector<std::string> mCleanups;
static bool mListenerFired;
control_group()
{
- mCG = new LLControlGroup("foo");
+ mCG.reset(new LLControlGroup("foo"));
LLUUID random;
random.generate();
// generate temp dir
- std::ostringstream oStr;
-
-#ifdef LL_WINDOWS
- char* tmp_dir = getenv("TMP");
- if(tmp_dir)
- {
- oStr << tmp_dir << "/llcontrol-test-" << random << "/";
- }
- else
- {
- oStr << "c:/tmp/llcontrol-test-" << random << "/";
- }
-#else
- oStr << "/tmp/llcontrol-test-" << random << "/";
-#endif
-
- mTestConfigDir = oStr.str();
+ mTestConfigDir = STRINGIZE(LLFile::tmpdir() << "llcontrol-test-" << random << "/");
mTestConfigFile = mTestConfigDir + "settings.xml";
LLFile::mkdir(mTestConfigDir);
LLSD config;
@@ -76,7 +64,12 @@ namespace tut
~control_group()
{
//Remove test files
- delete mCG;
+ for (auto filename : mCleanups)
+ {
+ LLFile::remove(filename);
+ }
+ LLFile::remove(mTestConfigFile);
+ LLFile::rmdir(mTestConfigDir);
}
void writeSettingsFile(const LLSD& config)
{
@@ -118,6 +111,7 @@ namespace tut
ensure_equals("value of changed setting", mCG->getU32("TestSetting"), 13);
LLControlGroup test_cg("foo2");
std::string temp_test_file = (mTestConfigDir + "setting_llsd_temp.xml");
+ mCleanups.push_back(temp_test_file);
mCG->saveToFile(temp_test_file.c_str(), TRUE);
results = test_cg.loadFromFile(temp_test_file.c_str());
ensure("number of changed settings loaded", (results == 1));
@@ -139,6 +133,7 @@ namespace tut
ensure_equals("value of changed setting", mCG->getU32("TestSetting"), 13);
LLControlGroup test_cg("foo3");
std::string temp_test_file = (mTestConfigDir + "setting_llsd_persist_temp.xml");
+ mCleanups.push_back(temp_test_file);
mCG->saveToFile(temp_test_file.c_str(), TRUE);
results = test_cg.loadFromFile(temp_test_file.c_str());
//If we haven't changed any settings, then we shouldn't have any settings to load
@@ -153,7 +148,7 @@ namespace tut
ensure("number of settings", (results == 1));
mCG->getControl("TestSetting")->getSignal()->connect(boost::bind(&this->handleListenerTest));
mCG->setU32("TestSetting", 13);
- ensure("listener fired on changed setting", mListenerFired);
+ ensure("listener fired on changed setting", mListenerFired);
}
}
diff --git a/indra/media_plugins/base/CMakeLists.txt b/indra/media_plugins/base/CMakeLists.txt
index 70c81d4023..7f2b82ffdd 100644
--- a/indra/media_plugins/base/CMakeLists.txt
+++ b/indra/media_plugins/base/CMakeLists.txt
@@ -48,5 +48,5 @@ set(media_plugin_base_HEADER_FILES
add_library(media_plugin_base
${media_plugin_base_SOURCE_FILES}
-)
+ )
diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt
index 5452fd9d1e..ce6278963d 100644
--- a/indra/media_plugins/cef/CMakeLists.txt
+++ b/indra/media_plugins/cef/CMakeLists.txt
@@ -81,7 +81,7 @@ list(APPEND media_plugin_cef_SOURCE_FILES ${media_plugin_cef_HEADER_FILES})
add_library(media_plugin_cef
SHARED
${media_plugin_cef_SOURCE_FILES}
-)
+ )
#add_dependencies(media_plugin_cef
# ${MEDIA_PLUGIN_BASE_LIBRARIES}
diff --git a/indra/media_plugins/example/CMakeLists.txt b/indra/media_plugins/example/CMakeLists.txt
index 6f5b28b8e9..eb067a7f6e 100644
--- a/indra/media_plugins/example/CMakeLists.txt
+++ b/indra/media_plugins/example/CMakeLists.txt
@@ -47,7 +47,7 @@ set(media_plugin_example_SOURCE_FILES
add_library(media_plugin_example
SHARED
${media_plugin_example_SOURCE_FILES}
-)
+ )
target_link_libraries(media_plugin_example
${LLPLUGIN_LIBRARIES}
diff --git a/indra/media_plugins/gstreamer010/CMakeLists.txt b/indra/media_plugins/gstreamer010/CMakeLists.txt
index 6d18814b1e..571eb57b24 100644
--- a/indra/media_plugins/gstreamer010/CMakeLists.txt
+++ b/indra/media_plugins/gstreamer010/CMakeLists.txt
@@ -56,7 +56,7 @@ set(media_plugin_gstreamer010_HEADER_FILES
add_library(media_plugin_gstreamer010
SHARED
${media_plugin_gstreamer010_SOURCE_FILES}
-)
+ )
target_link_libraries(media_plugin_gstreamer010
${LLPLUGIN_LIBRARIES}
diff --git a/indra/media_plugins/libvlc/CMakeLists.txt b/indra/media_plugins/libvlc/CMakeLists.txt
index d3e9243069..97392bbe08 100644
--- a/indra/media_plugins/libvlc/CMakeLists.txt
+++ b/indra/media_plugins/libvlc/CMakeLists.txt
@@ -48,7 +48,7 @@ set(media_plugin_libvlc_SOURCE_FILES
add_library(media_plugin_libvlc
SHARED
${media_plugin_libvlc_SOURCE_FILES}
-)
+ )
target_link_libraries(media_plugin_libvlc
${LLPLUGIN_LIBRARIES}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index ce8b662231..b5fcb18cfc 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -3,7 +3,14 @@
project(viewer)
include(00-Common)
+# DON'T move Linking.cmake to its place in the alphabetized list below: it
+# sets variables on which the 3p .cmake files depend.
+include(Linking)
+
include(Boost)
+if (BUGSPLAT_DB)
+ include(bugsplat)
+endif (BUGSPLAT_DB)
include(BuildPackagesInfo)
include(BuildVersion)
include(CMakeCopyIfDifferent)
@@ -16,7 +23,6 @@ include(GLOD)
include(Hunspell)
include(JsonCpp)
include(LLAppearance)
-include(LLBase)
include(LLAudio)
include(LLCA)
include(LLCharacter)
@@ -37,14 +43,12 @@ include(LLUI)
include(LLVFS)
include(LLWindow)
include(LLXML)
-include(Linking)
include(NDOF)
include(NVAPI)
include(OPENAL)
include(OpenGL)
include(OpenSSL)
include(PNG)
-include(Requests)
include(TemplateCheck)
include(UI)
include(UnixInstall)
@@ -93,6 +97,12 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
+if (BUGSPLAT_DB)
+ include_directories(
+ ${BUGSPLAT_INCLUDE_DIR}
+ )
+endif (BUGSPLAT_DB)
+
include_directories(SYSTEM
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
${LLXML_SYSTEM_INCLUDE_DIRS}
@@ -265,6 +275,7 @@ set(viewer_SOURCE_FILES
llfloatermemleak.cpp
llfloatermodelpreview.cpp
llfloatermodeluploadbase.cpp
+ llfloatermyscripts.cpp
llfloaternamedesc.cpp
llfloaternotificationsconsole.cpp
llfloaternotificationstabbed.cpp
@@ -532,6 +543,7 @@ set(viewer_SOURCE_FILES
llscrollingpanelparam.cpp
llscrollingpanelparambase.cpp
llsculptidsize.cpp
+ llsearchableui.cpp
llsearchcombobox.cpp
llsearchhistory.cpp
llsecapi.cpp
@@ -892,6 +904,7 @@ set(viewer_HEADER_FILES
llfloatermemleak.h
llfloatermodelpreview.h
llfloatermodeluploadbase.h
+ llfloatermyscripts.h
llfloaternamedesc.h
llfloaternotificationsconsole.h
llfloaternotificationstabbed.h
@@ -1148,6 +1161,7 @@ set(viewer_HEADER_FILES
llscrollingpanelparam.h
llscrollingpanelparambase.h
llsculptidsize.h
+ llsearchableui.h
llsearchcombobox.h
llsearchhistory.h
llsecapi.h
@@ -1360,6 +1374,14 @@ if (DARWIN)
# This should be compiled with the viewer.
LIST(APPEND viewer_SOURCE_FILES llappdelegate-objc.mm)
+ set_source_files_properties(
+ llappdelegate-objc.mm
+ PROPERTIES
+ COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}"
+ # BugsplatMac is a module, imported with @import. That language feature
+ # demands these switches.
+ COMPILE_FLAGS "-fmodules -fcxx-modules"
+ )
find_library(AGL_LIBRARY AGL)
find_library(APPKIT_LIBRARY AppKit)
@@ -1374,6 +1396,12 @@ if (DARWIN)
${COREAUDIO_LIBRARY}
)
+ if (BUGSPLAT_DB)
+ list(APPEND viewer_LIBRARIES
+ ${BUGSPLAT_LIBRARIES}
+ )
+ endif (BUGSPLAT_DB)
+
# Add resource files to the project.
set(viewer_RESOURCE_FILES
secondlife.icns
@@ -1399,6 +1427,11 @@ endif (DARWIN)
if (LINUX)
LIST(APPEND viewer_SOURCE_FILES llappviewerlinux.cpp)
+ set_source_files_properties(
+ llappviewerlinux.cpp
+ PROPERTIES
+ COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}"
+ )
LIST(APPEND viewer_SOURCE_FILES llappviewerlinux_api_dbus.cpp)
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")
@@ -1415,6 +1448,11 @@ if (WINDOWS)
llappviewerwin32.cpp
llwindebug.cpp
)
+ set_source_files_properties(
+ llappviewerwin32.cpp
+ PROPERTIES
+ COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}"
+ )
list(APPEND viewer_HEADER_FILES
llappviewerwin32.h
@@ -1551,7 +1589,6 @@ if (WINDOWS)
kernel32
odbc32
odbccp32
- ole32
oleaut32
shell32
Vfw32
@@ -1585,6 +1622,7 @@ endif (WINDOWS)
# from within the IDE.
set(viewer_XUI_FILES
skins/default/colors.xml
+ skins/default/default_languages.xml
skins/default/textures/textures.xml
)
file(GLOB DEFAULT_XUI_FILE_GLOB_LIST
@@ -1697,6 +1735,11 @@ if (SDL_FOUND)
)
endif (SDL_FOUND)
+if (BUGSPLAT_DB)
+ set_property(TARGET ${VIEWER_BINARY_NAME}
+ PROPERTY COMPILE_DEFINITIONS "LL_BUGSPLAT")
+endif (BUGSPLAT_DB)
+
# add package files
file(GLOB EVENT_HOST_SCRIPT_GLOB_LIST
${CMAKE_CURRENT_SOURCE_DIR}/../viewer_components/*.py)
@@ -1795,7 +1838,7 @@ if (WINDOWS)
${SHARED_LIB_STAGING_DIR}/Debug/fmodexL.dll
)
endif (FMODEX)
-
+
add_custom_command(
OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat
COMMAND ${PYTHON_EXECUTABLE}
@@ -1804,15 +1847,16 @@ if (WINDOWS)
--actions=copy
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
+ "--bugsplat=${BUGSPLAT_DB}"
--build=${CMAKE_CURRENT_BINARY_DIR}
--buildtype=${CMAKE_BUILD_TYPE}
+ "--channel=${VIEWER_CHANNEL}"
--configuration=${CMAKE_CFG_INTDIR}
--dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
--grid=${GRID}
- "--channel=${VIEWER_CHANNEL}"
- --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
--source=${CMAKE_CURRENT_SOURCE_DIR}
--touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/copy_touched.bat
+ --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
stage_third_party_libs
@@ -1830,24 +1874,9 @@ if (WINDOWS)
add_dependencies(${VIEWER_BINARY_NAME}
SLPlugin
- windows-crash-logger
+ windows-crash-logger
)
- # sets the 'working directory' for debugging from visual studio.
- if (NOT UNATTENDED)
- add_custom_command(
- TARGET ${VIEWER_BINARY_NAME} POST_BUILD
- COMMAND ${CMAKE_SOURCE_DIR}/tools/vstool/vstool.exe
- ARGS
- --solution
- ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.sln
- --workingdir
- ${VIEWER_BINARY_NAME}
- "${CMAKE_CURRENT_SOURCE_DIR}"
- COMMENT "Setting the ${VIEWER_BINARY_NAME} working directory for debugging."
- )
- endif (NOT UNATTENDED)
-
if (PACKAGE)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2
@@ -1870,15 +1899,16 @@ if (WINDOWS)
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
+ "--bugsplat=${BUGSPLAT_DB}"
--build=${CMAKE_CURRENT_BINARY_DIR}
--buildtype=${CMAKE_BUILD_TYPE}
"--channel=${VIEWER_CHANNEL}"
- --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
--configuration=${CMAKE_CFG_INTDIR}
--dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
--grid=${GRID}
--source=${CMAKE_CURRENT_SOURCE_DIR}
--touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/touched.bat
+ --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
DEPENDS
${VIEWER_BINARY_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
@@ -1909,8 +1939,8 @@ else (WINDOWS)
endif (WINDOWS)
# *NOTE: - this list is very sensitive to ordering, test carefully on all
-# platforms if you change the releative order of the entries here.
-# In particular, cmake 2.6.4 (when buidling with linux/makefile generators)
+# platforms if you change the relative order of the entries here.
+# In particular, cmake 2.6.4 (when building with linux/makefile generators)
# appears to sometimes de-duplicate redundantly listed dependencies improperly.
# To work around this, higher level modules should be listed before the modules
# that they depend upon. -brad
@@ -1985,6 +2015,12 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${LLAPPEARANCE_LIBRARIES}
)
+if (BUGSPLAT_DB)
+ target_link_libraries(${VIEWER_BINARY_NAME}
+ ${BUGSPLAT_LIBRARIES}
+ )
+endif (BUGSPLAT_DB)
+
set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
"Path to artwork files.")
@@ -2008,15 +2044,16 @@ if (LINUX)
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
+ "--bugsplat=${BUGSPLAT_DB}"
--build=${CMAKE_CURRENT_BINARY_DIR}
--buildtype=${CMAKE_BUILD_TYPE}
"--channel=${VIEWER_CHANNEL}"
- --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
--configuration=${CMAKE_CFG_INTDIR}
--dest=${CMAKE_CURRENT_BINARY_DIR}/packaged
--grid=${GRID}
--source=${CMAKE_CURRENT_SOURCE_DIR}
--touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched
+ --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
${COPY_INPUT_DEPENDENCIES}
@@ -2030,17 +2067,18 @@ if (LINUX)
COMMAND ${PYTHON_EXECUTABLE}
ARGS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
- --arch=${ARCH}
--actions=copy
+ --arch=${ARCH}
--artwork=${ARTWORK_DIR}
+ "--bugsplat=${BUGSPLAT_DB}"
--build=${CMAKE_CURRENT_BINARY_DIR}
--buildtype=${CMAKE_BUILD_TYPE}
+ "--channel=${VIEWER_CHANNEL}"
--configuration=${CMAKE_CFG_INTDIR}
--dest=${CMAKE_CURRENT_BINARY_DIR}/packaged
--grid=${GRID}
- "--channel=${VIEWER_CHANNEL}"
- --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
--source=${CMAKE_CURRENT_SOURCE_DIR}
+ --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
${COPY_INPUT_DEPENDENCIES}
@@ -2058,37 +2096,46 @@ if (LINUX)
endif (LINUX)
if (DARWIN)
- # These all get set with PROPERTIES
- set(product "Second Life")
- # this is the setting for the Python wrapper, see SL-322 and WRAPPER line in Info-SecondLife.plist
- if (PACKAGE)
- set(MACOSX_WRAPPER_EXECUTABLE_NAME "SL_Launcher")
- else (PACKAGE)
- # force the name of the actual executable to allow running it within Xcode for debugging
- set(MACOSX_WRAPPER_EXECUTABLE_NAME "../Resources/Second Life Viewer.app/Contents/MacOS/Second Life")
- endif (PACKAGE)
- set(MACOSX_BUNDLE_INFO_STRING "Second Life Viewer")
+ # These all get set with PROPERTIES. It's not that the property names are
+ # magically known to CMake -- it's that these names are referenced in the
+ # Info-SecondLife.plist file in the configure_file() directive below.
+ set(product "${VIEWER_CHANNEL}")
+ set(MACOSX_EXECUTABLE_NAME "${VIEWER_CHANNEL}")
+ set(MACOSX_BUNDLE_INFO_STRING "${VIEWER_CHANNEL}")
set(MACOSX_BUNDLE_ICON_FILE "secondlife.icns")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.secondlife.indra.viewer")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${VIEWER_CHANNEL} ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
set(MACOSX_BUNDLE_BUNDLE_NAME "SecondLife")
- set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}")
+ set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${VIEWER_SHORT_VERSION}${VIEWER_MACOSX_PHASE}${VIEWER_REVISION}")
- set(MACOSX_BUNDLE_COPYRIGHT "Copyright © Linden Research, Inc. 2007")
+ set(MACOSX_BUNDLE_COPYRIGHT "Copyright © Linden Research, Inc. 2018")
set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "SecondLife.nib")
set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "NSApplication")
+
+ # https://blog.kitware.com/upcoming-in-cmake-2-8-12-osx-rpath-support/
+ set(CMAKE_MACOSX_RPATH 1)
set_target_properties(
${VIEWER_BINARY_NAME}
PROPERTIES
OUTPUT_NAME "${product}"
+ # From Contents/MacOS/SecondLife, look in Contents/Frameworks
+ INSTALL_RPATH "@loader_path/../Frameworks"
+ # SIGH, as of 2018-05-24 (cmake 3.11.1) the INSTALL_RPATH property simply
+ # does not work. Try this:
+ LINK_FLAGS "-rpath @loader_path/../Frameworks"
MACOSX_BUNDLE_INFO_PLIST
"${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist"
)
+ set(VIEWER_APP_BUNDLE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app")
+ set(VIEWER_APP_EXE "${VIEWER_APP_BUNDLE}/Contents/MacOS/${product}")
+ set(VIEWER_APP_DSYM "${VIEWER_APP_EXE}.dSYM")
+ set(VIEWER_APP_XCARCHIVE "${VIEWER_APP_BUNDLE}/../${product}.xcarchive.zip")
+
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist"
- "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app/Contents/Info.plist"
+ "${VIEWER_APP_BUNDLE}/Contents/Info.plist"
)
add_custom_command(
@@ -2099,15 +2146,16 @@ if (DARWIN)
--actions=copy
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
+ "--bugsplat=${BUGSPLAT_DB}"
--build=${CMAKE_CURRENT_BINARY_DIR}
--buildtype=${CMAKE_BUILD_TYPE}
+ --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER}
+ "--channel=${VIEWER_CHANNEL}"
--configuration=${CMAKE_CFG_INTDIR}
- --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app
+ --dest=${VIEWER_APP_BUNDLE}
--grid=${GRID}
- "--channel=${VIEWER_CHANNEL}"
- --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
- --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER}
--source=${CMAKE_CURRENT_SOURCE_DIR}
+ --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
DEPENDS
${VIEWER_BINARY_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
@@ -2132,15 +2180,16 @@ if (DARWIN)
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
+ "--bugsplat=${BUGSPLAT_DB}"
--build=${CMAKE_CURRENT_BINARY_DIR}
--buildtype=${CMAKE_BUILD_TYPE}
+ "--channel=${VIEWER_CHANNEL}"
--configuration=${CMAKE_CFG_INTDIR}
- --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app
+ --dest=${VIEWER_APP_BUNDLE}
--grid=${GRID}
- "--channel=${VIEWER_CHANNEL}"
- --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
--source=${CMAKE_CURRENT_SOURCE_DIR}
--touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched
+ --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
${SIGNING_SETTING}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
@@ -2152,67 +2201,152 @@ if (INSTALL)
include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake)
endif (INSTALL)
-if (PACKAGE)
- set(SYMBOL_SEARCH_DIRS "")
- # Note that the path to VIEWER_SYMBOL_FILE must match that in ../../build.sh
- if (WINDOWS)
- list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
- set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-windows-$ENV{AUTOBUILD_ADDRSIZE}.tar.bz2")
- # slplugin.exe failing symbols dump - need to debug, might have to do with updated version of google breakpad
- # set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe")
- set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
- set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}")
- set(VIEWER_COPY_MANIFEST copy_w_viewer_manifest)
- endif (WINDOWS)
- if (DARWIN)
- list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
- # *TODO: Generate these search dirs in the cmake files related to each binary.
- list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}")
- list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}")
- list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}")
- set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-darwin-$ENV{AUTOBUILD_ADDRSIZE}.tar.bz2")
- set(VIEWER_EXE_GLOBS "'Second Life' SLPlugin mac-crash-logger")
- set(VIEWER_EXE_GLOBS "'Second Life' mac-crash-logger")
- set(VIEWER_LIB_GLOB "*.dylib")
- endif (DARWIN)
- if (LINUX)
- list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged")
- set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-linux-$ENV{AUTOBUILD_ADDRSIZE}.tar.bz2")
- set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin")
- set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin")
- set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*")
- set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
- endif (LINUX)
-
- if(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)
- if(CMAKE_CFG_INTDIR STREQUAL ".")
- set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE})
- else(CMAKE_CFG_INTDIR STREQUAL ".")
- # set LLBUILD_CONFIG to be a shell variable evaluated at build time
- # reflecting the configuration we are currently building.
- set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR})
- endif(CMAKE_CFG_INTDIR STREQUAL ".")
- add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
- COMMAND "${PYTHON_EXECUTABLE}"
- ARGS
- "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py"
- "${LLBUILD_CONFIG}"
- "${SYMBOL_SEARCH_DIRS}"
- "${VIEWER_EXE_GLOBS}"
- "${VIEWER_LIB_GLOB}"
- "${AUTOBUILD_INSTALL_DIR}/bin/dump_syms"
- "${VIEWER_SYMBOL_FILE}"
- DEPENDS generate_breakpad_symbols.py
- VERBATIM)
-
- add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}")
- add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}")
- if (WINDOWS OR LINUX)
- add_dependencies(generate_breakpad_symbols "${VIEWER_COPY_MANIFEST}")
- endif (WINDOWS OR LINUX)
- add_dependencies(llpackage generate_breakpad_symbols)
- endif(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)
-endif (PACKAGE)
+# Note that the conventional VIEWER_SYMBOL_FILE is set by ../../build.sh
+if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIEWER_SYMBOL_FILE)
+ if (NOT BUGSPLAT_DB)
+ # Breakpad symbol-file generation
+ set(SYMBOL_SEARCH_DIRS "")
+ if (WINDOWS)
+ list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
+ # slplugin.exe failing symbols dump - need to debug, might have to do with updated version of google breakpad
+ # set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe")
+ set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
+ set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}")
+ set(VIEWER_COPY_MANIFEST copy_w_viewer_manifest)
+ endif (WINDOWS)
+ if (DARWIN)
+ list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
+ # *TODO: Generate these search dirs in the cmake files related to each binary.
+ list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}")
+ list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}")
+ list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}")
+ set(VIEWER_EXE_GLOBS "'${product}' SLPlugin mac-crash-logger")
+ set(VIEWER_EXE_GLOBS "'${product}' mac-crash-logger")
+ set(VIEWER_LIB_GLOB "*.dylib")
+ endif (DARWIN)
+ if (LINUX)
+ list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged")
+ set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin")
+ set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin")
+ set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*")
+ set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
+ endif (LINUX)
+
+ if(CMAKE_CFG_INTDIR STREQUAL ".")
+ set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE})
+ else(CMAKE_CFG_INTDIR STREQUAL ".")
+ # set LLBUILD_CONFIG to be a shell variable evaluated at build time
+ # reflecting the configuration we are currently building.
+ set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR})
+ endif(CMAKE_CFG_INTDIR STREQUAL ".")
+ add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
+ COMMAND "${PYTHON_EXECUTABLE}"
+ ARGS
+ "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py"
+ "${LLBUILD_CONFIG}"
+ "${SYMBOL_SEARCH_DIRS}"
+ "${VIEWER_EXE_GLOBS}"
+ "${VIEWER_LIB_GLOB}"
+ "${AUTOBUILD_INSTALL_DIR}/bin/dump_syms"
+ "${VIEWER_SYMBOL_FILE}"
+ DEPENDS generate_breakpad_symbols.py
+ VERBATIM)
+
+ add_custom_target(generate_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" ${VIEWER_BINARY_NAME} "${VIEWER_COPY_MANIFEST}")
+ add_dependencies(generate_symbols ${VIEWER_BINARY_NAME})
+ if (WINDOWS OR LINUX)
+ add_dependencies(generate_symbols "${VIEWER_COPY_MANIFEST}")
+ endif (WINDOWS OR LINUX)
+
+ else (NOT BUGSPLAT_DB)
+ # BugSplat symbol-file generation
+ if (WINDOWS)
+ # Just pack up a tarball containing only the .pdb file for the
+ # executable. Because we intend to use cygwin tar, we must render
+ # VIEWER_SYMBOL_FILE in cygwin path syntax.
+ execute_process(COMMAND "cygpath" "-u" "${VIEWER_SYMBOL_FILE}"
+ OUTPUT_VARIABLE VIEWER_SYMBOL_FILE_CYGWIN
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND "cygpath" "-u" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
+ OUTPUT_VARIABLE PARENT_DIRECTORY_CYGWIN
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
+ # Use of 'tar ...j' here assumes VIEWER_SYMBOL_FILE endswith .tar.bz2;
+ # testing a string suffix is painful enough in CMake language that
+ # we'll continue assuming it until forced to generalize.
+ COMMAND "tar"
+ ARGS
+ "cjf"
+ "${VIEWER_SYMBOL_FILE_CYGWIN}"
+ "-C"
+ "${PARENT_DIRECTORY_CYGWIN}"
+ "secondlife-bin.pdb"
+ DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-bin.pdb"
+ COMMENT "Packing viewer PDB into ${VIEWER_SYMBOL_FILE_CYGWIN}"
+ )
+ add_custom_target(generate_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" ${VIEWER_BINARY_NAME})
+ add_dependencies(generate_symbols ${VIEWER_BINARY_NAME})
+ endif (WINDOWS)
+ if (DARWIN)
+ # Have to run dsymutil first, then pack up the resulting .dSYM directory
+ add_custom_command(OUTPUT "${VIEWER_APP_DSYM}"
+ COMMAND "dsymutil"
+ ARGS
+ ${VIEWER_APP_EXE}
+ COMMENT "Generating ${VIEWER_APP_DSYM}"
+ )
+ add_custom_target(dsym_generate DEPENDS "${VIEWER_APP_DSYM}")
+ add_dependencies(dsym_generate ${VIEWER_BINARY_NAME})
+ add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
+ # See above comments about "tar ...j"
+ COMMAND "tar"
+ ARGS
+ "cjf"
+ "${VIEWER_SYMBOL_FILE}"
+ "-C"
+ "${VIEWER_APP_DSYM}/.."
+ "${product}.dSYM"
+ DEPENDS "${VIEWER_APP_DSYM}"
+ COMMENT "Packing dSYM into ${VIEWER_SYMBOL_FILE}"
+ )
+ add_custom_target(dsym_tarball DEPENDS "${VIEWER_SYMBOL_FILE}")
+ add_dependencies(dsym_tarball dsym_generate)
+ add_custom_command(OUTPUT "${VIEWER_APP_XCARCHIVE}"
+ COMMAND "zip"
+ ARGS
+ "-r"
+ "${VIEWER_APP_XCARCHIVE}"
+ "."
+ WORKING_DIRECTORY "${VIEWER_APP_DSYM}/.."
+ DEPENDS "${VIEWER_APP_DSYM}"
+ COMMENT "Generating xcarchive.zip for upload to BugSplat"
+ )
+ add_custom_target(dsym_xcarchive DEPENDS "${VIEWER_APP_XCARCHIVE}")
+ add_dependencies(dsym_xcarchive dsym_generate)
+ # Have to create a stamp file, and depend on it, to force CMake to run
+ # the cleanup step.
+ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp"
+ COMMAND rm -rf "${VIEWER_APP_DSYM}"
+ COMMAND touch "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp"
+ DEPENDS "${VIEWER_SYMBOL_FILE}" "${VIEWER_APP_XCARCHIVE}"
+ COMMENT "Cleaning up dSYM"
+ )
+ add_custom_target(generate_symbols DEPENDS
+ "${VIEWER_APP_DSYM}"
+ "${VIEWER_SYMBOL_FILE}"
+ "${VIEWER_APP_XCARCHIVE}"
+ "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp"
+ )
+ add_dependencies(generate_symbols dsym_tarball dsym_xcarchive)
+ endif (DARWIN)
+ if (LINUX)
+ # TBD
+ endif (LINUX)
+ endif (NOT BUGSPLAT_DB)
+
+ # for both BUGSPLAT_DB and Breakpad
+ add_dependencies(llpackage generate_symbols)
+endif ()
if (LL_TESTS)
# To add a viewer unit test, just add the test .cpp file below
diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist
index af4cf26ac6..cfe9d991c5 100644
--- a/indra/newview/Info-SecondLife.plist
+++ b/indra/newview/Info-SecondLife.plist
@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
- <string>${MACOSX_WRAPPER_EXECUTABLE_NAME}</string>
+ <string>${MACOSX_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
@@ -21,7 +21,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
@@ -32,6 +32,8 @@
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+ <key>NSMicrophoneUsageDescription</key>
+ <string>For voice chat, you must grant permission for Second Life to use the microphone.</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 9b9a244206..f3b5af39e4 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.0.2
+6.1.1
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 3ad8b6cded..e8cac7842b 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -4404,6 +4404,17 @@
<key>Value</key>
<real>96.0</real>
</map>
+ <key>ForceAddressSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Force Windows update to 32-bit or 64-bit viewer.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>ForceAssetFail</key>
<map>
<key>Comment</key>
@@ -11340,6 +11351,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>MenuSearch</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide 'Search menus' field</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>GroupListShowIcons</key>
<map>
<key>Comment</key>
@@ -13587,7 +13609,7 @@
<key>UpdaterServiceURL</key>
<map>
<key>Comment</key>
- <string>Default location for the updater service.</string>
+ <string>Obsolete; no longer used.</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
@@ -14068,16 +14090,16 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>VerboseLogs</key>
+ <key>RegionCrossingInterpolationTime</key>
<map>
<key>Comment</key>
- <string>Display source file and line number for each log item for debugging purposes</string>
+ <string>How long to extrapolate object motion after crossing regions</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
- <string>Boolean</string>
+ <string>F32</string>
<key>Value</key>
- <integer>0</integer>
+ <integer>1</integer>
</map>
<key>VertexShaderEnable</key>
<map>
@@ -16260,7 +16282,7 @@
<string>if true, disables running the GPU benchmark at startup
(default to class 1)</string>
<key>Persist</key>
- <integer>0</integer>
+ <integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 14c8dba39f..d1d5301efe 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -18,8 +18,7 @@
;;
;; Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
;;
-;; NSIS Unicode 2.46.5 or higher required
-;; http://www.scratchpaper.com/
+;; NSIS 3 or higher required for Unicode support
;;
;; Author: James Cook, TankMaster Finesmith, Don Kjer, Callum Prentice
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -27,6 +26,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Compiler flags
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Unicode true
SetOverwrite on # Overwrite files
SetCompress auto # Compress if saves space
SetCompressor /solid lzma # Compress whole installer as one block
@@ -46,28 +46,33 @@ RequestExecutionLevel admin # For when we write to Program Files
;; (these files are in the same place as the nsi template but the python script generates a new nsi file in the
;; application directory so we have to add a path to these include files)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-!include "%%SOURCE%%\installers\windows\lang_da.nsi"
-!include "%%SOURCE%%\installers\windows\lang_de.nsi"
+;; Ansariel notes: "Under certain circumstances the installer will fall back
+;; to the first defined (aka default) language version. So you want to include
+;; en-us as first language file."
!include "%%SOURCE%%\installers\windows\lang_en-us.nsi"
+
+# Danish and Polish no longer supported by the viewer itself
+##!include "%%SOURCE%%\installers\windows\lang_da.nsi"
+!include "%%SOURCE%%\installers\windows\lang_de.nsi"
!include "%%SOURCE%%\installers\windows\lang_es.nsi"
!include "%%SOURCE%%\installers\windows\lang_fr.nsi"
!include "%%SOURCE%%\installers\windows\lang_ja.nsi"
!include "%%SOURCE%%\installers\windows\lang_it.nsi"
-!include "%%SOURCE%%\installers\windows\lang_pl.nsi"
+##!include "%%SOURCE%%\installers\windows\lang_pl.nsi"
!include "%%SOURCE%%\installers\windows\lang_pt-br.nsi"
!include "%%SOURCE%%\installers\windows\lang_ru.nsi"
!include "%%SOURCE%%\installers\windows\lang_tr.nsi"
!include "%%SOURCE%%\installers\windows\lang_zh.nsi"
# *TODO: Move these into the language files themselves
-LangString LanguageCode ${LANG_DANISH} "da"
+##LangString LanguageCode ${LANG_DANISH} "da"
LangString LanguageCode ${LANG_GERMAN} "de"
LangString LanguageCode ${LANG_ENGLISH} "en"
LangString LanguageCode ${LANG_SPANISH} "es"
LangString LanguageCode ${LANG_FRENCH} "fr"
LangString LanguageCode ${LANG_JAPANESE} "ja"
LangString LanguageCode ${LANG_ITALIAN} "it"
-LangString LanguageCode ${LANG_POLISH} "pl"
+##LangString LanguageCode ${LANG_POLISH} "pl"
LangString LanguageCode ${LANG_PORTUGUESEBR} "pt"
LangString LanguageCode ${LANG_RUSSIAN} "ru"
LangString LanguageCode ${LANG_TURKISH} "tr"
@@ -80,9 +85,12 @@ Name ${INSTNAME}
SubCaption 0 $(LicenseSubTitleSetup) # Override "license agreement" text
+!define MUI_ICON "%%SOURCE%%\installers\windows\install_icon.ico"
+!define MUI_UNICON "%%SOURCE%%\installers\windows\uninstall_icon.ico"
+
BrandingText " " # Bottom of window text
-Icon %%SOURCE%%\installers\windows\install_icon.ico
-UninstallIcon %%SOURCE%%\installers\windows\uninstall_icon.ico
+Icon "${MUI_ICON}"
+UninstallIcon "${MUI_UNICON}"
WindowIcon on # Show our icon in left corner
BGGradient off # No big background window
CRCCheck on # Make sure CRC is OK
@@ -90,20 +98,50 @@ InstProgressFlags smooth colored # New colored smooth look
SetOverwrite on # Overwrite files by default
AutoCloseWindow true # After all files install, close window
-# initial location of install (default when not already installed)
-# note: Now we defer looking for existing install until onInit when we
-# are able to engage the 32/64 registry function
-InstallDir "%%PROGRAMFILES%%\${INSTNAME}"
+# Registry key paths, ours and Microsoft's
+!define LINDEN_KEY "SOFTWARE\Linden Research, Inc."
+!define INSTNAME_KEY "${LINDEN_KEY}\${INSTNAME}"
+!define MSCURRVER_KEY "SOFTWARE\Microsoft\Windows\CurrentVersion"
+!define MSNTCURRVER_KEY "SOFTWARE\Microsoft\Windows NT\CurrentVersion"
+!define MSUNINSTALL_KEY "${MSCURRVER_KEY}\Uninstall\${INSTNAME}"
+
+# from http://nsis.sourceforge.net/Docs/MultiUser/Readme.html
+### Highest level permitted for user: Admin for Admin, Standard for Standard
+##!define MULTIUSER_EXECUTIONLEVEL Highest
+!define MULTIUSER_EXECUTIONLEVEL Admin
+!define MULTIUSER_MUI
+### Look for /AllUsers or /CurrentUser switches
+##!define MULTIUSER_INSTALLMODE_COMMANDLINE
+# appended to $PROGRAMFILES, as affected by MULTIUSER_USE_PROGRAMFILES64
+!define MULTIUSER_INSTALLMODE_INSTDIR "${INSTNAME}"
+# expands to !define MULTIUSER_USE_PROGRAMFILES64 or nothing
+%%PROGRAMFILES%%
+# should make MultiUser.nsh initialization read existing INSTDIR from registry
+## SL-10506: don't
+##!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "${INSTNAME_KEY}"
+##!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME ""
+# Don't set MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY and
+# MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME to cause the installer to
+# write $MultiUser.InstallMode to the registry, because when the user installs
+# multiple viewers with the same channel (same ${INSTNAME}, hence same
+# ${INSTNAME_KEY}), the registry entry is overwritten. Instead we'll write a
+# little file into the install directory -- see .onInstSuccess and un.onInit.
+!include MultiUser.nsh
+!include MUI2.nsh
+!define MUI_BGCOLOR FFFFFF
+!insertmacro MUI_FUNCTION_GUIINIT
UninstallText $(UninstallTextMsg)
DirText $(DirectoryChooseTitle) $(DirectoryChooseSetup)
-Page directory dirPre
-Page instfiles
+##!insertmacro MULTIUSER_PAGE_INSTALLMODE
+!define MUI_PAGE_CUSTOMFUNCTION_PRE dirPre
+!insertmacro MUI_PAGE_DIRECTORY
+!insertmacro MUI_PAGE_INSTFILES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Variables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Var INSTPROG
+Var INSTNAME
Var INSTEXE
Var VIEWER_EXE
Var INSTSHORTCUT
@@ -142,17 +180,21 @@ FunctionEnd
;; entry to the language ID selector below
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function .onInit
+!insertmacro MULTIUSER_INIT
%%ENGAGEREGISTRY%%
-# read the current location of the install for this version
+# SL-10506: Setting MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY and
+# MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME should
+# read the current location of the install for this version into INSTDIR.
+# However, SL-10506 complains about the resulting behavior, so the logic below
+# is adapted from before we introduced MultiUser.nsh.
+
# if $0 is empty, this is the first time for this viewer name
-ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\\Linden Research, Inc.\\${INSTNAME}" ""
+ReadRegStr $0 SHELL_CONTEXT "${INSTNAME_KEY}" ""
-# viewer with this name not installed before
-${If} $0 == ""
- # nothing to do here
-${Else}
+# viewer with this name was installed before
+${If} $0 != ""
# use the value we got from registry as install location
StrCpy $INSTDIR $0
${EndIf}
@@ -181,7 +223,7 @@ Call CheckWindowsVersion # Don't install On unsupported systems
lbl_configure_default_lang:
# If we currently have a version of SL installed, default to the language of that install
# Otherwise don't change $LANGUAGE and it will default to the OS UI language.
- ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage"
+ ReadRegStr $0 SHELL_CONTEXT "${INSTNAME_KEY}" "InstallerLanguage"
IfErrors +2 0 # If error skip the copy instruction
StrCpy $LANGUAGE $0
@@ -191,7 +233,6 @@ lbl_configure_default_lang:
Goto lbl_return
StrCmp $SKIP_DIALOGS "true" lbl_return
-lbl_build_menu:
Push ""
# Use separate file so labels can be UTF-16 but we can still merge changes into this ASCII file. JC
!include "%%SOURCE%%\installers\windows\language_menu.nsi"
@@ -204,7 +245,7 @@ lbl_build_menu:
StrCpy $LANGUAGE $0
# Save language in registry
- WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" $LANGUAGE
+ WriteRegStr SHELL_CONTEXT "${INSTNAME_KEY}" "InstallerLanguage" $LANGUAGE
lbl_return:
Pop $0
Return
@@ -215,14 +256,32 @@ FunctionEnd
;; Prep Uninstaller Section
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function un.onInit
+ # Save $INSTDIR -- it appears to have the correct value before
+ # MULTIUSER_UNINIT, but then gets munged by MULTIUSER_UNINIT?!
+ Push $INSTDIR
+ !insertmacro MULTIUSER_UNINIT
+ Pop $INSTDIR
+
+ # Now read InstallMode.txt from $INSTDIR
+ Push $0
+ ClearErrors
+ FileOpen $0 "$INSTDIR\InstallMode.txt" r
+ IfErrors skipread
+ FileRead $0 $MultiUser.InstallMode
+ FileClose $0
+skipread:
+ Pop $0
%%ENGAGEREGISTRY%%
# Read language from registry and set for uninstaller. Key will be removed on successful uninstall
- ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage"
+ ReadRegStr $0 SHELL_CONTEXT "${INSTNAME_KEY}" "InstallerLanguage"
IfErrors lbl_end
StrCpy $LANGUAGE $0
lbl_end:
+
+## MessageBox MB_OK "After restoring:$\n$$INSTDIR = '$INSTDIR'$\n$$MultiUser.InstallMode = '$MultiUser.InstallMode'$\n$$LANGUAGE = '$LANGUAGE'"
+
Return
FunctionEnd
@@ -272,10 +331,10 @@ FunctionEnd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Section ""
-SetShellVarContext all # Install for all users (if you change this, change it in the uninstall as well)
+# SetShellVarContext is set by MultiUser.nsh initialization.
# Start with some default values.
-StrCpy $INSTPROG "${INSTNAME}"
+StrCpy $INSTNAME "${INSTNAME}"
StrCpy $INSTEXE "${INSTEXE}"
StrCpy $VIEWER_EXE "${VIEWER_EXE}"
StrCpy $INSTSHORTCUT "${SHORTCUT}"
@@ -299,7 +358,7 @@ StrCpy $SHORTCUT_LANG_PARAM "--set InstallLanguage $(LanguageCode)"
CreateDirectory "$SMPROGRAMS\$INSTSHORTCUT"
SetOutPath "$INSTDIR"
CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT.lnk" \
- "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+ "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
WriteINIStr "$SMPROGRAMS\$INSTSHORTCUT\SL Create Account.url" \
@@ -317,31 +376,31 @@ CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\Uninstall $INSTSHORTCUT.lnk" \
# Other shortcuts
SetOutPath "$INSTDIR"
CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" \
- "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+ "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" \
- "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+ "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \
'"$INSTDIR\uninst.exe"' ''
# Write registry
-WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "" "$INSTDIR"
-WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" "${VERSION_LONG}"
-WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut" "$INSTSHORTCUT"
-WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe" "$INSTEXE"
-WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "Publisher" "Linden Research, Inc."
-WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "URLInfoAbout" "http://secondlife.com/whatis/"
-WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "URLUpdateInfo" "http://secondlife.com/support/downloads/"
-WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "HelpLink" "https://support.secondlife.com/contact-support/"
-WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayName" "$INSTPROG"
-WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "UninstallString" '"$INSTDIR\uninst.exe"'
-WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayVersion" "${VERSION_LONG}"
-WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "EstimatedSize" "0x0001D500" # ~117 MB
+WriteRegStr SHELL_CONTEXT "${INSTNAME_KEY}" "" "$INSTDIR"
+WriteRegStr SHELL_CONTEXT "${INSTNAME_KEY}" "Version" "${VERSION_LONG}"
+WriteRegStr SHELL_CONTEXT "${INSTNAME_KEY}" "Shortcut" "$INSTSHORTCUT"
+WriteRegStr SHELL_CONTEXT "${INSTNAME_KEY}" "Exe" "$VIEWER_EXE"
+WriteRegStr SHELL_CONTEXT "${MSUNINSTALL_KEY}" "Publisher" "Linden Research, Inc."
+WriteRegStr SHELL_CONTEXT "${MSUNINSTALL_KEY}" "URLInfoAbout" "http://secondlife.com/whatis/"
+WriteRegStr SHELL_CONTEXT "${MSUNINSTALL_KEY}" "URLUpdateInfo" "http://secondlife.com/support/downloads/"
+WriteRegStr SHELL_CONTEXT "${MSUNINSTALL_KEY}" "HelpLink" "https://support.secondlife.com/contact-support/"
+WriteRegStr SHELL_CONTEXT "${MSUNINSTALL_KEY}" "DisplayName" "$INSTNAME"
+WriteRegStr SHELL_CONTEXT "${MSUNINSTALL_KEY}" "UninstallString" '"$INSTDIR\uninst.exe"'
+WriteRegStr SHELL_CONTEXT "${MSUNINSTALL_KEY}" "DisplayVersion" "${VERSION_LONG}"
+WriteRegDWORD SHELL_CONTEXT "${MSUNINSTALL_KEY}" "EstimatedSize" "0x0001D500" # ~117 MB
# from FS:Ansariel
-WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayIcon" '"$INSTDIR\$INSTEXE"'
+WriteRegStr SHELL_CONTEXT "${MSUNINSTALL_KEY}" "DisplayIcon" '"$INSTDIR\$VIEWER_EXE"'
# BUG-2707 Disable SEHOP for installed viewer.
-WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$INSTEXE" "DisableExceptionChainValidation" 1
+WriteRegDWORD SHELL_CONTEXT "${MSNTCURRVER_KEY}\Image File Execution Options\$VIEWER_EXE" "DisableExceptionChainValidation" 1
# Write URL registry info
WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "(default)" "URL:Second Life"
@@ -358,9 +417,8 @@ WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\DefaultIcon" "" '"$INSTDIR\$
# URL param must be last item passed to viewer, it ignores subsequent params to avoid parameter injection attacks.
WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open\command" "" '"$INSTDIR\$VIEWER_EXE" -url "%1"'
-# Only allow Launcher to be the icon
-WriteRegStr HKEY_CLASSES_ROOT "Applications\$INSTEXE" "IsHostApp" ""
-WriteRegStr HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}" "NoStartPage" ""
+WriteRegStr HKEY_CLASSES_ROOT "Applications\$VIEWER_EXE" "IsHostApp" ""
+##WriteRegStr HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}" "NoStartPage" ""
# Write out uninstaller
WriteUninstaller "$INSTDIR\uninst.exe"
@@ -381,25 +439,32 @@ SectionEnd
Section Uninstall
# Start with some default values.
-StrCpy $INSTPROG "${INSTNAME}"
+StrCpy $INSTNAME "${INSTNAME}"
StrCpy $INSTEXE "${INSTEXE}"
+StrCpy $VIEWER_EXE "${VIEWER_EXE}"
StrCpy $INSTSHORTCUT "${SHORTCUT}"
-# Make sure the user can install/uninstall
-Call un.CheckIfAdministrator
-
-# Uninstall for all users (if you change this, change it in the install as well)
-SetShellVarContext all
+# SetShellVarContext per the mode saved at install time in registry at
+# MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY
+# MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME
+# Couldn't get NSIS to expand $MultiUser.InstallMode into the function name at Call time
+${If} $MultiUser.InstallMode == 'AllUsers'
+##MessageBox MB_OK "Uninstalling for all users"
+ Call un.MultiUser.InstallMode.AllUsers
+${Else}
+##MessageBox MB_OK "Uninstalling for current user"
+ Call un.MultiUser.InstallMode.CurrentUser
+${EndIf}
# Make sure we're not running
Call un.CloseSecondLife
# Clean up registry keys and subkeys (these should all be !defines somewhere)
-DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG"
-DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG"
+DeleteRegKey SHELL_CONTEXT "${INSTNAME_KEY}"
+DeleteRegKey SHELL_CONTEXT "${MSCURRVER_KEY}\Uninstall\$INSTNAME"
# BUG-2707 Remove entry that disabled SEHOP
-DeleteRegKey HKEY_LOCAL_MACHINE "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$INSTEXE"
-DeleteRegKey HKEY_CLASSES_ROOT "Applications\$INSTEXE"
+DeleteRegKey SHELL_CONTEXT "${MSNTCURRVER_KEY}\Image File Execution Options\$VIEWER_EXE"
+##DeleteRegKey HKEY_CLASSES_ROOT "Applications\$INSTEXE"
DeleteRegKey HKEY_CLASSES_ROOT "Applications\${VIEWER_EXE}"
# Clean up shortcuts
@@ -537,6 +602,7 @@ Function RemoveProgFilesOnInst
# Remove old SecondLife.exe to invalidate any old shortcuts to it that may be in non-standard locations. See MAINT-3575
Delete "$INSTDIR\$INSTEXE"
+Delete "$INSTDIR\$VIEWER_EXE"
# Remove old shader files first so fallbacks will work. See DEV-5663
RMDir /r "$INSTDIR\app_settings\shaders"
@@ -570,10 +636,10 @@ Push $2
StrCpy $0 0 # Index number used to iterate via EnumRegKey
LOOP:
- EnumRegKey $1 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $0
+ EnumRegKey $1 SHELL_CONTEXT "${MSNTCURRVER_KEY}\ProfileList" $0
StrCmp $1 "" DONE # No more users
- ReadRegStr $2 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$1" "ProfileImagePath"
+ ReadRegStr $2 SHELL_CONTEXT "${MSNTCURRVER_KEY}\ProfileList\$1" "ProfileImagePath"
StrCmp $2 "" CONTINUE 0 # "ProfileImagePath" value is missing
# Required since ProfileImagePath is of type REG_EXPAND_SZ
@@ -603,7 +669,7 @@ Pop $0
# Delete files in ProgramData\Secondlife
Push $0
- ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" "Common AppData"
+ ReadRegStr $0 SHELL_CONTEXT "${MSCURRVER_KEY}\Explorer\Shell Folders" "Common AppData"
StrCmp $0 "" +2
RMDir /r "$0\SecondLife"
Pop $0
@@ -624,6 +690,9 @@ Function un.ProgramFiles
# This placeholder is replaced by the complete list of files to uninstall by viewer_manifest.py
%%DELETE_FILES%%
+# our InstallMode.txt
+Delete "$INSTDIR\InstallMode.txt"
+
# Optional/obsolete files. Delete won't fail if they don't exist.
Delete "$INSTDIR\autorun.bat"
Delete "$INSTDIR\dronesettings.ini"
@@ -651,17 +720,15 @@ RMDir "$INSTDIR"
IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER
FOLDERFOUND:
-# Silent uninstall always removes all files (/SD IDYES)
- MessageBox MB_YESNO $(DeleteProgramFilesMB) /SD IDYES IDNO NOFOLDER
- RMDir /r "$INSTDIR"
+ MessageBox MB_OK $(DeleteProgramFilesMB) /SD IDOK IDOK NOFOLDER
NOFOLDER:
MessageBox MB_YESNO $(DeleteRegistryKeysMB) IDYES DeleteKeys IDNO NoDelete
DeleteKeys:
- DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Classes\x-grid-location-info"
- DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Classes\secondlife"
+ DeleteRegKey SHELL_CONTEXT "SOFTWARE\Classes\x-grid-location-info"
+ DeleteRegKey SHELL_CONTEXT "SOFTWARE\Classes\secondlife"
DeleteRegKey HKEY_CLASSES_ROOT "x-grid-location-info"
DeleteRegKey HKEY_CLASSES_ROOT "secondlife"
@@ -673,7 +740,13 @@ FunctionEnd
;; After install completes, launch app
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function .onInstSuccess
-Call CheckWindowsServPack # Warn if not on the latest SP before asking to launch.
+ Push $0
+ FileOpen $0 "$INSTDIR\InstallMode.txt" w
+ # No newline -- this is for our use, not for users to read.
+ FileWrite $0 "$MultiUser.InstallMode"
+ FileClose $0
+ Pop $0
+
Push $R0
Push $0
;; MAINT-7812: Only write nsis.winstall file with /marker switch
@@ -692,11 +765,24 @@ Call CheckWindowsServPack # Warn if not on the latest SP before asking to launc
ClearErrors
Pop $0
Pop $R0
- Push $R0 # Option value, unused#
+
+ Call CheckWindowsServPack # Warn if not on the latest SP before asking to launch.
StrCmp $SKIP_AUTORUN "true" +2;
-# Assumes SetOutPath $INSTDIR
- Exec '"$WINDIR\explorer.exe" "$INSTDIR\$INSTSHORTCUT.lnk"'
- Pop $R0
+ # Assumes SetOutPath $INSTDIR
+ # Run INSTEXE (our updater), passing VIEWER_EXE plus the command-line
+ # arguments built into our shortcuts. This gives the updater a chance
+ # to verify that the viewer we just installed is appropriate for the
+ # running system -- or, if not, to download and install a different
+ # viewer. For instance, if a user running 32-bit Windows installs a
+ # 64-bit viewer, it cannot run on this system. But since the updater
+ # is a 32-bit executable even in the 64-bit viewer package, the
+ # updater can detect the problem and adapt accordingly.
+ # Once everything is in order, the updater will run the specified
+ # viewer with the specified params.
+ # Quote the updater executable and the viewer executable because each
+ # must be a distinct command-line token, but DO NOT quote the language
+ # string because it must decompose into separate command-line tokens.
+ Exec '"$INSTDIR\$INSTEXE" precheck "$INSTDIR\$VIEWER_EXE" $SHORTCUT_LANG_PARAM'
#
FunctionEnd
@@ -733,10 +819,10 @@ FunctionEnd
; StrCpy $0 0 # Index number used to iterate via EnumRegKey
;
; LOOP:
-; EnumRegKey $1 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $0
+; EnumRegKey $1 SHELL_CONTEXT "${MSNTCURRVER_KEY}\ProfileList" $0
; StrCmp $1 "" DONE # no more users
;
-; ReadRegStr $2 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$1" "ProfileImagePath"
+; ReadRegStr $2 SHELL_CONTEXT "${MSNTCURRVER_KEY}\ProfileList\$1" "ProfileImagePath"
; StrCmp $2 "" CONTINUE 0 # "ProfileImagePath" value is missing
;
;# Required since ProfileImagePath is of type REG_EXPAND_SZ
@@ -755,7 +841,7 @@ FunctionEnd
;
;# Copy files in Documents and Settings\All Users\SecondLife
;Push $0
-; ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" "Common AppData"
+; ReadRegStr $0 SHELL_CONTEXT "${MSCURRVER_KEY}\Explorer\Shell Folders" "Common AppData"
; StrCmp $0 "" +2
; RMDir /r "$2\Application Data\SecondLife\"
;Pop $0
diff --git a/indra/newview/installers/windows/lang_da.nsi b/indra/newview/installers/windows/lang_da.nsi
index 83e1a3ea94..f462c82078 100644
--- a/indra/newview/installers/windows/lang_da.nsi
+++ b/indra/newview/installers/windows/lang_da.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/lang_de.nsi b/indra/newview/installers/windows/lang_de.nsi
index 2a868acc89..8bb20476b3 100644..100755
--- a/indra/newview/installers/windows/lang_de.nsi
+++ b/indra/newview/installers/windows/lang_de.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/lang_en-us.nsi b/indra/newview/installers/windows/lang_en-us.nsi
index 00aa47de69..fd4d340816 100644
--- a/indra/newview/installers/windows/lang_en-us.nsi
+++ b/indra/newview/installers/windows/lang_en-us.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/lang_es.nsi b/indra/newview/installers/windows/lang_es.nsi
index 1ecf254ffb..8a81110069 100644..100755
--- a/indra/newview/installers/windows/lang_es.nsi
+++ b/indra/newview/installers/windows/lang_es.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/lang_fr.nsi b/indra/newview/installers/windows/lang_fr.nsi
index bec5835bed..f038c0e419 100644..100755
--- a/indra/newview/installers/windows/lang_fr.nsi
+++ b/indra/newview/installers/windows/lang_fr.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/lang_it.nsi b/indra/newview/installers/windows/lang_it.nsi
index 1d2e150525..bd16d8318f 100644..100755
--- a/indra/newview/installers/windows/lang_it.nsi
+++ b/indra/newview/installers/windows/lang_it.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/lang_ja.nsi b/indra/newview/installers/windows/lang_ja.nsi
index 1bd6526670..71edde1992 100644..100755
--- a/indra/newview/installers/windows/lang_ja.nsi
+++ b/indra/newview/installers/windows/lang_ja.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/lang_pl.nsi b/indra/newview/installers/windows/lang_pl.nsi
index a172f0cdeb..05977847b9 100644
--- a/indra/newview/installers/windows/lang_pl.nsi
+++ b/indra/newview/installers/windows/lang_pl.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/lang_pt-br.nsi b/indra/newview/installers/windows/lang_pt-br.nsi
index 87032fec18..0e7cbeacda 100644..100755
--- a/indra/newview/installers/windows/lang_pt-br.nsi
+++ b/indra/newview/installers/windows/lang_pt-br.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/lang_ru.nsi b/indra/newview/installers/windows/lang_ru.nsi
index 019c66123c..d55aacc971 100644..100755
--- a/indra/newview/installers/windows/lang_ru.nsi
+++ b/indra/newview/installers/windows/lang_ru.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/lang_tr.nsi b/indra/newview/installers/windows/lang_tr.nsi
index 1c4e2c2f48..4746f84482 100644..100755
--- a/indra/newview/installers/windows/lang_tr.nsi
+++ b/indra/newview/installers/windows/lang_tr.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/lang_zh.nsi b/indra/newview/installers/windows/lang_zh.nsi
index 355e01a333..397bd0ac81 100644..100755
--- a/indra/newview/installers/windows/lang_zh.nsi
+++ b/indra/newview/installers/windows/lang_zh.nsi
Binary files differ
diff --git a/indra/newview/installers/windows/language_menu.nsi b/indra/newview/installers/windows/language_menu.nsi
index 08ad42532f..2f426a0f47 100644
--- a/indra/newview/installers/windows/language_menu.nsi
+++ b/indra/newview/installers/windows/language_menu.nsi
Binary files differ
diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm
index aebae4c434..1d55537427 100644
--- a/indra/newview/llappdelegate-objc.mm
+++ b/indra/newview/llappdelegate-objc.mm
@@ -25,7 +25,16 @@
*/
#import "llappdelegate-objc.h"
+#if defined(LL_BUGSPLAT)
+#include <boost/filesystem.hpp>
+#include <vector>
+@import BugsplatMac;
+// derived from BugsplatMac's BugsplatTester/AppDelegate.m
+@interface LLAppDelegate () <BugsplatStartupManagerDelegate>
+@end
+#endif
#include "llwindowmacosx-objc.h"
+#include "llappviewermacosx-for-objc.h"
#include <Carbon/Carbon.h> // Used for Text Input Services ("Safe" API - it's supported)
@implementation LLAppDelegate
@@ -47,6 +56,25 @@
- (void) applicationDidFinishLaunching:(NSNotification *)notification
{
+ // Call constructViewer() first so our logging subsystem is in place. This
+ // risks missing crashes in the LLAppViewerMacOSX constructor, but for
+ // present purposes it's more important to get the startup sequence
+ // properly logged.
+ // Someday I would like to modify the logging system so that calls before
+ // it's initialized are cached in a std::ostringstream and then, once it's
+ // initialized, "played back" into whatever handlers have been set up.
+ constructViewer();
+
+#if defined(LL_BUGSPLAT)
+ // Engage BugsplatStartupManager *before* calling initViewer() to handle
+ // any crashes during initialization.
+ // https://www.bugsplat.com/docs/platforms/os-x#initialization
+ [BugsplatStartupManager sharedManager].autoSubmitCrashReport = YES;
+ [BugsplatStartupManager sharedManager].askUserDetails = NO;
+ [BugsplatStartupManager sharedManager].delegate = self;
+ [[BugsplatStartupManager sharedManager] start];
+#endif
+
frameTimer = nil;
[self languageUpdated];
@@ -179,4 +207,138 @@
return true;
}
+#if defined(LL_BUGSPLAT)
+
+- (NSString *)applicationLogForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager
+{
+ CrashMetadata& meta(CrashMetadata_instance());
+ // As of BugsplatMac 1.0.6, userName and userEmail properties are now
+ // exposed by the BugsplatStartupManager. Set them here, since the
+ // defaultUserNameForBugsplatStartupManager and
+ // defaultUserEmailForBugsplatStartupManager methods are called later, for
+ // the *current* run, rather than for the previous crashed run whose crash
+ // report we are about to send.
+ infos("applicationLogForBugsplatStartupManager setting userName = '" +
+ meta.agentFullname + '"');
+ bugsplatStartupManager.userName =
+ [NSString stringWithCString:meta.agentFullname.c_str()
+ encoding:NSUTF8StringEncoding];
+ // Use the email field for OS version, just as we do on Windows, until
+ // BugSplat provides more metadata fields.
+ infos("applicationLogForBugsplatStartupManager setting userEmail = '" +
+ meta.OSInfo + '"');
+ bugsplatStartupManager.userEmail =
+ [NSString stringWithCString:meta.OSInfo.c_str()
+ encoding:NSUTF8StringEncoding];
+ // This strangely-named override method's return value contributes the
+ // User Description metadata field.
+ infos("applicationLogForBugsplatStartupManager -> '" + meta.fatalMessage + "'");
+ return [NSString stringWithCString:meta.fatalMessage.c_str()
+ encoding:NSUTF8StringEncoding];
+}
+
+- (NSString *)applicationKeyForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager signal:(NSString *)signal exceptionName:(NSString *)exceptionName exceptionReason:(NSString *)exceptionReason {
+ // TODO: exceptionName, exceptionReason
+
+ // Windows sends location within region as well, but that's because
+ // BugSplat for Windows intercepts crashes during the same run, and that
+ // information can be queried once. On the Mac, any metadata we have is
+ // written (and rewritten) to the static_debug_info.log file that we read
+ // at the start of the next viewer run. It seems ridiculously expensive to
+ // rewrite that file on every frame in which the avatar moves.
+ std::string regionName(CrashMetadata_instance().regionName);
+ infos("applicationKeyForBugsplatStartupManager -> '" + regionName + "'");
+ return [NSString stringWithCString:regionName.c_str()
+ encoding:NSUTF8StringEncoding];
+}
+
+- (NSString *)defaultUserNameForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager {
+ std::string agentFullname(CrashMetadata_instance().agentFullname);
+ infos("defaultUserNameForBugsplatStartupManager -> '" + agentFullname + "'");
+ return [NSString stringWithCString:agentFullname.c_str()
+ encoding:NSUTF8StringEncoding];
+}
+
+- (NSString *)defaultUserEmailForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager {
+ // Use the email field for OS version, just as we do on Windows, until
+ // BugSplat provides more metadata fields.
+ std::string OSInfo(CrashMetadata_instance().OSInfo);
+ infos("defaultUserEmailForBugsplatStartupManager -> '" + OSInfo + "'");
+ return [NSString stringWithCString:OSInfo.c_str()
+ encoding:NSUTF8StringEncoding];
+}
+
+- (void)bugsplatStartupManagerWillSendCrashReport:(BugsplatStartupManager *)bugsplatStartupManager
+{
+ infos("bugsplatStartupManagerWillSendCrashReport");
+}
+
+struct AttachmentInfo
+{
+ AttachmentInfo(const std::string& path, const std::string& type):
+ pathname(path),
+ basename(boost::filesystem::path(path).filename().string()),
+ mimetype(type)
+ {}
+
+ std::string pathname, basename, mimetype;
+};
+
+- (NSArray<BugsplatAttachment *> *)attachmentsForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager
+{
+ const CrashMetadata& metadata(CrashMetadata_instance());
+
+ // Since we must do very similar processing for each of several file
+ // pathnames, start by collecting them into a vector so we can iterate
+ // instead of spelling out the logic for each.
+ std::vector<AttachmentInfo> info{
+ AttachmentInfo(metadata.logFilePathname, "text/plain"),
+ AttachmentInfo(metadata.userSettingsPathname, "text/xml"),
+ AttachmentInfo(metadata.staticDebugPathname, "text/xml")
+ };
+
+ // We "happen to know" that info[0].basename is "SecondLife.old" -- due to
+ // the fact that BugsplatMac only notices a crash during the viewer run
+ // following the crash. Replace .old with .log to reduce confusion.
+ info[0].basename =
+ boost::filesystem::path(info[0].pathname).stem().string() + ".log";
+
+ NSMutableArray *attachments = [[NSMutableArray alloc] init];
+
+ // Iterate over each AttachmentInfo in info vector
+ for (const AttachmentInfo& attach : info)
+ {
+ NSString *nspathname = [NSString stringWithCString:attach.pathname.c_str()
+ encoding:NSUTF8StringEncoding];
+ NSString *nsbasename = [NSString stringWithCString:attach.basename.c_str()
+ encoding:NSUTF8StringEncoding];
+ NSString *nsmimetype = [NSString stringWithCString:attach.mimetype.c_str()
+ encoding:NSUTF8StringEncoding];
+ NSData *nsdata = [NSData dataWithContentsOfFile:nspathname];
+
+ BugsplatAttachment *attachment =
+ [[BugsplatAttachment alloc] initWithFilename:nsbasename
+ attachmentData:nsdata
+ contentType:nsmimetype];
+
+ [attachments addObject:attachment];
+ infos("attachmentsForBugsplatStartupManager attaching " + attach.pathname);
+ }
+
+ return attachments;
+}
+
+- (void)bugsplatStartupManagerDidFinishSendingCrashReport:(BugsplatStartupManager *)bugsplatStartupManager
+{
+ infos("Sent crash report to BugSplat");
+}
+
+- (void)bugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager didFailWithError:(NSError *)error
+{
+ // TODO: message string from NSError
+ infos("Could not send crash report to BugSplat");
+}
+
+#endif // LL_BUGSPLAT
+
@end
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 4374caacdf..b7e2f17c46 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -568,12 +568,12 @@ static void settings_to_globals()
LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures");
- LLVOVolume::sLODFactor = gSavedSettings.getF32("RenderVolumeLODFactor");
+ LLVOVolume::sLODFactor = llclamp(gSavedSettings.getF32("RenderVolumeLODFactor"), 0.01f, MAX_LOD_FACTOR);
LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f;
LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor");
LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor");
- LLVOAvatar::sLODFactor = gSavedSettings.getF32("RenderAvatarLODFactor");
- LLVOAvatar::sPhysicsLODFactor = gSavedSettings.getF32("RenderAvatarPhysicsLODFactor");
+ LLVOAvatar::sLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR);
+ LLVOAvatar::sPhysicsLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarPhysicsLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR);
LLVOAvatar::updateImpostorRendering(gSavedSettings.getU32("RenderAvatarMaxNonImpostors"));
LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible");
// clamp auto-open time to some minimum usable value
@@ -707,6 +707,22 @@ LLAppViewer::LLAppViewer()
//
LLLoginInstance::instance().setPlatformInfo(gPlatform, LLOSInfo::instance().getOSVersionString(), LLOSInfo::instance().getOSStringSimple());
+
+ // Under some circumstances we want to read the static_debug_info.log file
+ // from the previous viewer run between this constructor call and the
+ // init() call, which will overwrite the static_debug_info.log file for
+ // THIS run. So setDebugFileNames() early.
+#if LL_BUGSPLAT
+ // MAINT-8917: don't create a dump directory just for the
+ // static_debug_info.log file
+ std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
+#else // ! LL_BUGSPLAT
+ // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues.
+ std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
+#endif // ! LL_BUGSPLAT
+ mDumpPath = logdir;
+ setMiniDumpDir(logdir);
+ setDebugFileNames(logdir);
}
LLAppViewer::~LLAppViewer()
@@ -781,13 +797,6 @@ bool LLAppViewer::init()
initMaxHeapSize() ;
LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize"));
- // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues.
- std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
- mDumpPath = logdir;
- setMiniDumpDir(logdir);
- logdir += gDirUtilp->getDirDelimiter();
- setDebugFileNames(logdir);
-
// Although initLoggingAndGetLastDuration() is the right place to mess with
// setFatalFunction(), we can't query gSavedSettings until after
@@ -876,11 +885,6 @@ bool LLAppViewer::init()
mNumSessions++;
gSavedSettings.setS32("NumSessions", mNumSessions);
- if (gSavedSettings.getBOOL("VerboseLogs"))
- {
- LLError::setPrintLocation(true);
- }
-
// LLKeyboard relies on LLUI to know what some accelerator keys are called.
LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString );
@@ -1083,26 +1087,6 @@ bool LLAppViewer::init()
}
}
-// don't nag developers who need to run the executable directly
-#if LL_RELEASE_FOR_DOWNLOAD
- // MAINT-8305: If we're processing a SLURL, skip the launcher check.
- if (gSavedSettings.getString("CmdLineLoginLocation").empty() && !beingDebugged())
- {
- const char* PARENT = getenv("PARENT");
- if (! (PARENT && std::string(PARENT) == "SL_Launcher"))
- {
- // Don't directly run this executable. Please run the launcher, which
- // will run the viewer itself.
- // Naturally we do not consider this bulletproof. The point is to
- // gently remind a user who *inadvertently* finds him/herself in this
- // situation to do things the Right Way. Anyone who intentionally
- // bypasses this mechanism needs no reminder that s/he's shooting
- // him/herself in the foot.
- LLNotificationsUtil::add("RunLauncher");
- }
- }
-#endif
-
#if LL_WINDOWS
if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion())
{
@@ -1150,6 +1134,34 @@ bool LLAppViewer::init()
gGLActive = FALSE;
+ LLProcess::Params updater;
+ updater.desc = "updater process";
+ // Because it's the updater, it MUST persist beyond the lifespan of the
+ // viewer itself.
+ updater.autokill = false;
+#if LL_WINDOWS
+ updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "SLVersionChecker.exe");
+#elif LL_DARWIN
+ // explicitly run the system Python interpreter on SLVersionChecker.py
+ updater.executable = "python";
+ updater.args.add(gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", "SLVersionChecker.py"));
+#else
+ updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "SLVersionChecker");
+#endif
+ // add LEAP mode command-line argument to whichever of these we selected
+ updater.args.add("leap");
+ // UpdaterServiceSettings
+ updater.args.add(stringize(gSavedSettings.getU32("UpdaterServiceSetting")));
+ // channel
+ updater.args.add(LLVersionInfo::getChannel());
+ // testok
+ updater.args.add(stringize(gSavedSettings.getBOOL("UpdaterWillingToTest")));
+ // ForceAddressSize
+ updater.args.add(stringize(gSavedSettings.getU32("ForceAddressSize")));
+
+ // Run the updater. An exception from launching the updater should bother us.
+ LLLeap::create(updater, true);
+
// Iterate over --leap command-line options. But this is a bit tricky: if
// there's only one, it won't be an array at all.
LLSD LeapCommand(gSavedSettings.getLLSD("LeapCommand"));
@@ -1693,7 +1705,7 @@ bool LLAppViewer::cleanup()
release_start_screen(); // just in case
- LLError::logToFixedBuffer(NULL);
+ LLError::logToFixedBuffer(NULL); // stop the fixed buffer recorder
LL_INFOS() << "Cleaning Up" << LL_ENDL;
@@ -2148,7 +2160,7 @@ bool LLAppViewer::initThreads()
if (LLTrace::BlockTimer::sLog || LLTrace::BlockTimer::sMetricLog)
{
- LLTrace::BlockTimer::setLogLock(new LLMutex(NULL));
+ LLTrace::BlockTimer::setLogLock(new LLMutex());
mFastTimerLogThread = new LLFastTimerLogThread(LLTrace::BlockTimer::sLogName);
mFastTimerLogThread->start();
}
@@ -2172,6 +2184,12 @@ void errorCallback(const std::string &error_string)
//Set the ErrorActivated global so we know to create a marker file
gLLErrorActivated = true;
+ gDebugInfo["FatalMessage"] = error_string;
+ // We're not already crashing -- we simply *intend* to crash. Since we
+ // haven't actually trashed anything yet, we can afford to write the whole
+ // static info file.
+ LLAppViewer::instance()->writeDebugInfo();
+
LLError::crashAndLoop(error_string);
}
@@ -3039,14 +3057,11 @@ void LLAppViewer::writeDebugInfo(bool isStatic)
? getStaticDebugFile()
: getDynamicDebugFile() );
- LL_INFOS() << "Opening debug file " << *debug_filename << LL_ENDL;
- llofstream out_file(debug_filename->c_str());
+ LL_INFOS() << "Writing debug file " << *debug_filename << LL_ENDL;
+ llofstream out_file(debug_filename->c_str());
isStatic ? LLSDSerialize::toPrettyXML(gDebugInfo, out_file)
: LLSDSerialize::toPrettyXML(gDebugInfo["Dynamic"], out_file);
-
-
- out_file.close();
}
LLSD LLAppViewer::getViewerInfo() const
@@ -5439,7 +5454,8 @@ void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs)
{
if(secs < 0.0f)
{
- secs = gSavedSettings.getF32("MainloopTimeoutDefault");
+ static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60);
+ secs = mainloop_timeout;
}
mMainloopTimeout->setTimeout(secs);
@@ -5466,7 +5482,8 @@ void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs)
{
if(secs < 0.0f)
{
- secs = gSavedSettings.getF32("MainloopTimeoutDefault");
+ static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60);
+ secs = mainloop_timeout;
}
mMainloopTimeout->setTimeout(secs);
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index e607b4a994..788fe6a19b 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -43,6 +43,7 @@
#define LL_LLAPPVIEWER_H
#include "llallocator.h"
+#include "llapr.h"
#include "llcontrol.h"
#include "llsys.h" // for LLOSInfo
#include "lltimer.h"
diff --git a/indra/newview/llappviewermacosx-for-objc.h b/indra/newview/llappviewermacosx-for-objc.h
new file mode 100644
index 0000000000..37e8a3917a
--- /dev/null
+++ b/indra/newview/llappviewermacosx-for-objc.h
@@ -0,0 +1,53 @@
+/**
+ * @file llappviewermacosx-for-objc.h
+ * @author Nat Goodspeed
+ * @date 2018-06-15
+ * @brief llappviewermacosx.h publishes the C++ API for
+ * llappviewermacosx.cpp, just as
+ * llappviewermacosx-objc.h publishes the Objective-C++ API for
+ * llappviewermacosx-objc.mm.
+ *
+ * This header is intended to publish for Objective-C++ consumers a
+ * subset of the C++ API presented by llappviewermacosx.cpp. It's a
+ * subset because, if an Objective-C++ consumer were to #include
+ * the full llappviewermacosx.h, we would almost surely run into
+ * trouble due to the discrepancy between Objective-C++'s BOOL versus
+ * classic Microsoft/Linden BOOL.
+ *
+ * $LicenseInfo:firstyear=2018&license=viewerlgpl$
+ * Copyright (c) 2018, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLAPPVIEWERMACOSX_FOR_OBJC_H)
+#define LL_LLAPPVIEWERMACOSX_FOR_OBJC_H
+
+#include <string>
+
+void constructViewer();
+bool initViewer();
+void handleUrl(const char* url_utf8);
+bool pumpMainLoop();
+void handleQuit();
+void cleanupViewer();
+void infos(const std::string& message);
+
+// This struct is malleable; it only serves as a way to convey a number of
+// fields from llappviewermacosx.cpp's CrashMetadata_instance() function to the
+// consuming functions in llappdelegate-objc.mm. As long as both those sources
+// are compiled with this same header, the content and order of CrashMetadata
+// can change as needed.
+struct CrashMetadata
+{
+ std::string logFilePathname;
+ std::string userSettingsPathname;
+ std::string staticDebugPathname;
+ std::string OSInfo;
+ std::string agentFullname;
+ std::string regionName;
+ std::string fatalMessage;
+};
+
+CrashMetadata& CrashMetadata_instance();
+
+#endif /* ! defined(LL_LLAPPVIEWERMACOSX_FOR_OBJC_H) */
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index d472f8926b..3111540a13 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -36,20 +36,25 @@
#include "llappviewermacosx-objc.h"
#include "llappviewermacosx.h"
+#include "llappviewermacosx-for-objc.h"
#include "llwindowmacosx-objc.h"
#include "llcommandlineparser.h"
+#include "llsdserialize.h"
#include "llviewernetwork.h"
#include "llviewercontrol.h"
#include "llmd5.h"
#include "llfloaterworldmap.h"
#include "llurldispatcher.h"
+#include "llerrorcontrol.h"
+#include "llvoavatarself.h" // for gAgentAvatarp->getFullname()
#include <ApplicationServices/ApplicationServices.h>
#ifdef LL_CARBON_CRASH_HANDLER
#include <Carbon/Carbon.h>
#endif
#include <vector>
#include <exception>
+#include <fstream>
#include "lldir.h"
#include <signal.h>
@@ -81,7 +86,7 @@ static void exceptionTerminateHandler()
gOldTerminateHandler(); // call old terminate() handler
}
-bool initViewer()
+void constructViewer()
{
// Set the working dir to <bundle>/Contents/Resources
if (chdir(gDirUtilp->getAppRODataDir().c_str()) == -1)
@@ -97,18 +102,20 @@ bool initViewer()
gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
gViewerAppPtr->setErrorHandler(LLAppViewer::handleViewerCrash);
+}
-
+bool initViewer()
+{
bool ok = gViewerAppPtr->init();
if(!ok)
{
LL_WARNS() << "Application init failed." << LL_ENDL;
}
- else if (!gHandleSLURL.empty())
- {
- dispatchUrl(gHandleSLURL);
- gHandleSLURL = "";
- }
+ else if (!gHandleSLURL.empty())
+ {
+ dispatchUrl(gHandleSLURL);
+ gHandleSLURL = "";
+ }
return ok;
}
@@ -147,6 +154,73 @@ void cleanupViewer()
gViewerAppPtr = NULL;
}
+// The BugsplatMac API is structured as a number of different method
+// overrides, each returning a different piece of metadata. But since we
+// obtain such metadata by opening and parsing a file, it seems ridiculous to
+// reopen and reparse it for every individual string desired. What we want is
+// to open and parse the file once, retaining the data for subsequent
+// requests. That's why this is an LLSingleton.
+// Another approach would be to provide a function that simply returns
+// CrashMetadata, storing the struct in LLAppDelegate, but nat doesn't know
+// enough Objective-C++ to code that. We'd still have to detect which of the
+// method overrides is called first so that the results are order-insensitive.
+class CrashMetadataSingleton: public CrashMetadata, public LLSingleton<CrashMetadataSingleton>
+{
+ LLSINGLETON(CrashMetadataSingleton);
+
+ // convenience method to log each metadata field retrieved by constructor
+ std::string get_metadata(const LLSD& info, const LLSD::String& key) const
+ {
+ std::string data(info[key].asString());
+ LL_INFOS() << " " << key << "='" << data << "'" << LL_ENDL;
+ return data;
+ }
+};
+
+// Populate the fields of our public base-class struct.
+CrashMetadataSingleton::CrashMetadataSingleton()
+{
+ // Note: we depend on being able to read the static_debug_info.log file
+ // from the *previous* run before we overwrite it with the new one for
+ // *this* run. LLAppViewer initialization must happen in the Right Order.
+ staticDebugPathname = *gViewerAppPtr->getStaticDebugFile();
+ std::ifstream static_file(staticDebugPathname);
+ LLSD info;
+ if (! static_file.is_open())
+ {
+ LL_INFOS() << "Can't open '" << staticDebugPathname
+ << "'; no metadata about previous run" << LL_ENDL;
+ }
+ else if (! LLSDSerialize::deserialize(info, static_file, LLSDSerialize::SIZE_UNLIMITED))
+ {
+ LL_INFOS() << "Can't parse '" << staticDebugPathname
+ << "'; no metadata about previous run" << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "Metadata from '" << staticDebugPathname << "':" << LL_ENDL;
+ logFilePathname = get_metadata(info, "SLLog");
+ userSettingsPathname = get_metadata(info, "SettingsFilename");
+ OSInfo = get_metadata(info, "OSInfo");
+ agentFullname = get_metadata(info, "LoginName");
+ // Translate underscores back to spaces
+ LLStringUtil::replaceChar(agentFullname, '_', ' ');
+ regionName = get_metadata(info, "CurrentRegion");
+ fatalMessage = get_metadata(info, "FatalMessage");
+ }
+}
+
+// Avoid having to compile all of our LLSingleton machinery in Objective-C++.
+CrashMetadata& CrashMetadata_instance()
+{
+ return CrashMetadataSingleton::instance();
+}
+
+void infos(const std::string& message)
+{
+ LL_INFOS() << message << LL_ENDL;
+}
+
int main( int argc, char **argv )
{
// Store off the command line args for use later.
@@ -337,68 +411,6 @@ std::string LLAppViewerMacOSX::generateSerialNumber()
return serial_md5;
}
-static AudioDeviceID get_default_audio_output_device(void)
-{
- AudioDeviceID device = 0;
- UInt32 size = sizeof(device);
- AudioObjectPropertyAddress device_address = { kAudioHardwarePropertyDefaultOutputDevice,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
-
- OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &device_address, 0, NULL, &size, &device);
- if(err != noErr)
- {
- LL_DEBUGS("SystemMute") << "Couldn't get default audio output device (0x" << std::hex << err << ")" << LL_ENDL;
- }
-
- return device;
-}
-
-//virtual
-void LLAppViewerMacOSX::setMasterSystemAudioMute(bool new_mute)
-{
- AudioDeviceID device = get_default_audio_output_device();
-
- if(device != 0)
- {
- UInt32 mute = new_mute;
- AudioObjectPropertyAddress device_address = { kAudioDevicePropertyMute,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster };
-
- OSStatus err = AudioObjectSetPropertyData(device, &device_address, 0, NULL, sizeof(mute), &mute);
- if(err != noErr)
- {
- LL_INFOS("SystemMute") << "Couldn't set audio mute property (0x" << std::hex << err << ")" << LL_ENDL;
- }
- }
-}
-
-//virtual
-bool LLAppViewerMacOSX::getMasterSystemAudioMute()
-{
- // Assume the system isn't muted
- UInt32 mute = 0;
-
- AudioDeviceID device = get_default_audio_output_device();
-
- if(device != 0)
- {
- UInt32 size = sizeof(mute);
- AudioObjectPropertyAddress device_address = { kAudioDevicePropertyMute,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster };
-
- OSStatus err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &size, &mute);
- if(err != noErr)
- {
- LL_DEBUGS("SystemMute") << "Couldn't get audio mute property (0x" << std::hex << err << ")" << LL_ENDL;
- }
- }
-
- return (mute != 0);
-}
-
void handleUrl(const char* url_utf8)
{
if (url_utf8 && gViewerAppPtr)
diff --git a/indra/newview/llappviewermacosx.h b/indra/newview/llappviewermacosx.h
index ebb41a495c..d5a80864be 100644
--- a/indra/newview/llappviewermacosx.h
+++ b/indra/newview/llappviewermacosx.h
@@ -42,10 +42,6 @@ public:
//
virtual bool init(); // Override to do application initialization
- // mute/unmute the system's master audio
- virtual void setMasterSystemAudioMute(bool mute);
- virtual bool getMasterSystemAudioMute();
-
protected:
virtual bool restoreErrorTrap();
virtual void initCrashReporting(bool reportFreeze);
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 3942613ee0..fff2653c98 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -66,8 +66,101 @@
#endif
#include "stringize.h"
+#include "lldir.h"
+#include "llerrorcontrol.h"
+#include <fstream>
#include <exception>
+
+// Bugsplat (http://bugsplat.com) crash reporting tool
+#ifdef LL_BUGSPLAT
+#include "BugSplat.h"
+#include "reader.h" // JsonCpp
+#include "llagent.h" // for agent location
+#include "llviewerregion.h"
+#include "llvoavatarself.h" // for agent name
+
+namespace
+{
+ // MiniDmpSender's constructor is defined to accept __wchar_t* instead of
+ // plain wchar_t*. That said, wunder() returns std::basic_string<__wchar_t>,
+ // NOT plain __wchar_t*, despite the apparent convenience. Calling
+ // wunder(something).c_str() as an argument expression is fine: that
+ // std::basic_string instance will survive until the function returns.
+ // Calling c_str() on a std::basic_string local to wunder() would be
+ // Undefined Behavior: we'd be left with a pointer into a destroyed
+ // std::basic_string instance. But we can do that with a macro...
+ #define WCSTR(string) wunder(string).c_str()
+
+ // It would be nice if, when wchar_t is the same as __wchar_t, this whole
+ // function would optimize away. However, we use it only for the arguments
+ // to the BugSplat API -- a handful of calls.
+ inline std::basic_string<__wchar_t> wunder(const std::wstring& str)
+ {
+ return { str.begin(), str.end() };
+ }
+
+ // when what we have in hand is a std::string, convert from UTF-8 using
+ // specific wstringize() overload
+ inline std::basic_string<__wchar_t> wunder(const std::string& str)
+ {
+ return wunder(wstringize(str));
+ }
+
+ // Irritatingly, MiniDmpSender::setCallback() is defined to accept a
+ // classic-C function pointer instead of an arbitrary C++ callable. If it
+ // did accept a modern callable, we could pass a lambda that binds our
+ // MiniDmpSender pointer. As things stand, though, we must define an
+ // actual function and store the pointer statically.
+ static MiniDmpSender *sBugSplatSender = nullptr;
+
+ bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2)
+ {
+ if (nCode == MDSCB_EXCEPTIONCODE)
+ {
+ // send the main viewer log file
+ // widen to wstring, convert to __wchar_t, then pass c_str()
+ sBugSplatSender->sendAdditionalFile(
+ WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log")));
+
+ sBugSplatSender->sendAdditionalFile(
+ WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml")));
+
+ sBugSplatSender->sendAdditionalFile(
+ WCSTR(*LLAppViewer::instance()->getStaticDebugFile()));
+
+ // We don't have an email address for any user. Hijack this
+ // metadata field for the platform identifier.
+ sBugSplatSender->setDefaultUserEmail(
+ WCSTR(STRINGIZE(LLOSInfo::instance().getOSStringSimple() << " ("
+ << ADDRESS_SIZE << "-bit)")));
+
+ if (gAgentAvatarp)
+ {
+ // user name, when we have it
+ sBugSplatSender->setDefaultUserName(WCSTR(gAgentAvatarp->getFullname()));
+ }
+
+ // LL_ERRS message, when there is one
+ sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage()));
+
+ if (gAgent.getRegion())
+ {
+ // region location, when we have it
+ LLVector3 loc = gAgent.getPositionAgent();
+ sBugSplatSender->resetAppIdentifier(
+ WCSTR(STRINGIZE(gAgent.getRegion()->getName()
+ << '/' << loc.mV[0]
+ << '/' << loc.mV[1]
+ << '/' << loc.mV[2])));
+ }
+ } // MDSCB_EXCEPTIONCODE
+
+ return false;
+ }
+}
+#endif // LL_BUGSPLAT
+
namespace
{
void (*gOldTerminateHandler)() = NULL;
@@ -495,15 +588,71 @@ bool LLAppViewerWin32::init()
LLWinDebug::instance();
#endif
-#if LL_WINDOWS
#if LL_SEND_CRASH_REPORTS
-
+#if ! defined(LL_BUGSPLAT)
+#pragma message("Building without BugSplat")
LLAppViewer* pApp = LLAppViewer::instance();
pApp->initCrashReporting();
-#endif
-#endif
+#else // LL_BUGSPLAT
+#pragma message("Building with BugSplat")
+
+ std::string build_data_fname(
+ gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json"));
+ // Use llifstream instead of std::ifstream because LL_PATH_EXECUTABLE
+ // could contain non-ASCII characters, which std::ifstream doesn't handle.
+ llifstream inf(build_data_fname.c_str());
+ if (! inf.is_open())
+ {
+ LL_WARNS() << "Can't initialize BugSplat, can't read '" << build_data_fname
+ << "'" << LL_ENDL;
+ }
+ else
+ {
+ Json::Reader reader;
+ Json::Value build_data;
+ if (! reader.parse(inf, build_data, false)) // don't collect comments
+ {
+ // gah, the typo is baked into Json::Reader API
+ LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname
+ << "': " << reader.getFormatedErrorMessages() << LL_ENDL;
+ }
+ else
+ {
+ Json::Value BugSplat_DB = build_data["BugSplat DB"];
+ if (! BugSplat_DB)
+ {
+ LL_WARNS() << "Can't initialize BugSplat, no 'BugSplat DB' entry in '"
+ << build_data_fname << "'" << LL_ENDL;
+ }
+ else
+ {
+ // Got BugSplat_DB, onward!
+ std::wstring version_string(WSTRINGIZE(LL_VIEWER_VERSION_MAJOR << '.' <<
+ LL_VIEWER_VERSION_MINOR << '.' <<
+ LL_VIEWER_VERSION_PATCH << '.' <<
+ LL_VIEWER_VERSION_BUILD));
+
+ // have to convert normal wide strings to strings of __wchar_t
+ sBugSplatSender = new MiniDmpSender(
+ WCSTR(BugSplat_DB.asString()),
+ WCSTR(LL_TO_WSTRING(LL_VIEWER_CHANNEL)),
+ WCSTR(version_string),
+ nullptr, // szAppIdentifier -- set later
+ MDSF_NONINTERACTIVE | // automatically submit report without prompting
+ MDSF_PREVENTHIJACKING); // disallow swiping Exception filter
+ sBugSplatSender->setCallback(bugsplatSendLog);
+
+ // engage stringize() overload that converts from wstring
+ LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL)
+ << ' ' << stringize(version_string) << ')' << LL_ENDL;
+ } // got BugSplat_DB
+ } // parsed build_data.json
+ } // opened build_data.json
+
+#endif // LL_BUGSPLAT
+#endif // LL_SEND_CRASH_REPORTS
bool success = LLAppViewer::init();
diff --git a/indra/newview/llautoreplace.cpp b/indra/newview/llautoreplace.cpp
index dd9354fe3a..0516520c56 100644
--- a/indra/newview/llautoreplace.cpp
+++ b/indra/newview/llautoreplace.cpp
@@ -68,8 +68,8 @@ void LLAutoReplace::autoreplaceCallback(S32& replacement_start, S32& replacement
word_start--; // walk word_start back to the beginning of the word
}
LL_DEBUGS("AutoReplace") << "word_start: " << word_start << " word_end: " << word_end << LL_ENDL;
- std::string str_text = std::string(input_text.begin(), input_text.end());
- std::string last_word = str_text.substr(word_start, word_end - word_start + 1);
+ LLWString old_string = input_text.substr(word_start, word_end - word_start + 1);
+ std::string last_word = wstring_to_utf8str(old_string);
std::string replacement_word(mSettings.replaceWord(last_word));
if (replacement_word != last_word)
@@ -79,9 +79,8 @@ void LLAutoReplace::autoreplaceCallback(S32& replacement_start, S32& replacement
{
// return the replacement string
replacement_start = word_start;
- replacement_length = last_word.length();
+ replacement_length = word_end - word_start + 1;
replacement_string = utf8str_to_wstring(replacement_word);
- LLWString old_string = utf8str_to_wstring(last_word);
S32 size_change = replacement_string.size() - old_string.size();
cursor_pos += size_change;
}
diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp
index eddc87efcd..4f42868f1a 100644
--- a/indra/newview/llchatitemscontainerctrl.cpp
+++ b/indra/newview/llchatitemscontainerctrl.cpp
@@ -29,6 +29,7 @@
#include "llchatitemscontainerctrl.h"
#include "lltextbox.h"
+#include "llavataractions.h"
#include "llavatariconctrl.h"
#include "llcommandhandler.h"
#include "llfloaterreg.h"
@@ -204,6 +205,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification)
mMsgText = getChild<LLChatMsgBox>("msg_text", false);
mMsgText->setContentTrusted(false);
+ mMsgText->setIsFriendCallback(LLAvatarActions::isFriend);
mMsgText->setText(std::string(""));
diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index d3fd5813a0..0f02c23cb0 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -60,6 +60,8 @@ LLControlAvatar::LLControlAvatar(const LLUUID& id, const LLPCode pcode, LLViewer
// virtual
LLControlAvatar::~LLControlAvatar()
{
+ // Should already have been unlinked before destruction
+ llassert(!mRootVolp);
}
// virtual
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index ebbbf23dee..c258136889 100644
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -351,7 +351,7 @@ void LLConversationItemSession::setParticipantIsMuted(const LLUUID& participant_
LLConversationItemParticipant* participant = findParticipant(participant_id);
if (participant)
{
- participant->muteVoice(is_muted);
+ participant->moderateVoice(is_muted);
}
}
@@ -498,6 +498,7 @@ void LLConversationItemSession::onAvatarNameCache(const LLAvatarName& av_name)
LLConversationItemParticipant::LLConversationItemParticipant(std::string display_name, const LLUUID& uuid, LLFolderViewModelInterface& root_view_model) :
LLConversationItem(display_name,uuid,root_view_model),
+ mIsModeratorMuted(false),
mIsModerator(false),
mDisplayModeratorLabel(false),
mDistToAgent(-1.0)
@@ -508,6 +509,7 @@ LLConversationItemParticipant::LLConversationItemParticipant(std::string display
LLConversationItemParticipant::LLConversationItemParticipant(const LLUUID& uuid, LLFolderViewModelInterface& root_view_model) :
LLConversationItem(uuid,root_view_model),
+ mIsModeratorMuted(false),
mIsModerator(false),
mDisplayModeratorLabel(false),
mDistToAgent(-1.0)
@@ -597,25 +599,7 @@ void LLConversationItemParticipant::setDisplayModeratorRole(bool displayRole)
bool LLConversationItemParticipant::isVoiceMuted()
{
- return LLMuteList::getInstance()->isMuted(mUUID, LLMute::flagVoiceChat);
-}
-
-void LLConversationItemParticipant::muteVoice(bool mute_voice)
-{
- LLAvatarName av_name;
- LLAvatarNameCache::get(mUUID, &av_name);
- LLMuteList * mute_listp = LLMuteList::getInstance();
- bool voice_already_muted = mute_listp->isMuted(mUUID, av_name.getUserName());
-
- LLMute mute(mUUID, av_name.getUserName(), LLMute::AGENT);
- if (voice_already_muted && !mute_voice)
- {
- mute_listp->remove(mute);
- }
- else if (!voice_already_muted && mute_voice)
- {
- mute_listp->add(mute);
- }
+ return mIsModeratorMuted || LLMuteList::getInstance()->isMuted(mUUID, LLMute::flagVoiceChat);
}
//
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index 3868bafae4..80385fad5f 100644
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -194,8 +194,9 @@ public:
virtual const std::string& getDisplayName() const { return mDisplayName; }
bool isVoiceMuted();
+ bool isModeratorMuted() { return mIsModeratorMuted; }
bool isModerator() const { return mIsModerator; }
- void muteVoice(bool mute_voice);
+ void moderateVoice(bool mute_voice) { mIsModeratorMuted = mute_voice; }
void setIsModerator(bool is_moderator) { mIsModerator = is_moderator; mNeedsRefresh = true; }
void setTimeNow() { mLastActiveTime = LLFrameTimer::getElapsedSeconds(); mNeedsRefresh = true; }
void setDistance(F64 dist) { mDistToAgent = dist; mNeedsRefresh = true; }
@@ -216,6 +217,7 @@ private:
void onAvatarNameCache(const LLAvatarName& av_name); // callback used by fetchAvatarName
void updateName(const LLAvatarName& av_name);
+ bool mIsModeratorMuted; // default is false
bool mIsModerator; // default is false
bool mDisplayModeratorLabel; // default is false
std::string mDisplayName;
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index 15a8aacd37..59bb9af744 100644
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -234,6 +234,8 @@ void LLConversationViewSession::draw()
// Draw children if root folder, or any other folder that is open. Do not draw children when animating to closed state or you get rendering overlap.
bool draw_children = getRoot() == static_cast<LLFolderViewFolder*>(this) || isOpen();
+ // Todo/fix this: arrange hides children 'out of bonds', session 'slowly' adjusts container size, unhides children
+ // this process repeats until children fit
for (folders_t::iterator iter = mFolders.begin();
iter != mFolders.end();)
{
@@ -254,9 +256,6 @@ void LLConversationViewSession::draw()
updateLabelRotation();
drawOpenFolderArrow(default_params, sFgColor);
}
-
- refresh();
-
LLView::draw();
}
@@ -568,6 +567,7 @@ void LLConversationViewParticipant::draw()
F32 text_left = (F32)getLabelXPos();
LLColor4 color;
+
LLLocalSpeakerMgr *speakerMgr = LLLocalSpeakerMgr::getInstance();
if (speakerMgr && speakerMgr->isSpeakerToBeRemoved(mUUID))
@@ -579,9 +579,14 @@ void LLConversationViewParticipant::draw()
color = mIsSelected ? sHighlightFgColor : sFgColor;
}
+ LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(getViewModelItem());
+ if (participant_model)
+ {
+ mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted());
+ }
+
drawHighlight(show_context, mIsSelected, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
drawLabel(font, text_left, y, color, right_x);
- refresh();
LLView::draw();
}
@@ -605,6 +610,20 @@ S32 LLConversationViewParticipant::arrange(S32* width, S32* height)
return arranged;
}
+// virtual
+void LLConversationViewParticipant::refresh()
+{
+ // Refresh the participant view from its model data
+ LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(getViewModelItem());
+ participant_model->resetRefresh();
+
+ // *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat
+ mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted());
+
+ // Do the regular upstream refresh
+ LLFolderViewItem::refresh();
+}
+
void LLConversationViewParticipant::addToFolder(LLFolderViewFolder* folder)
{
// Add the item to the folder (conversation)
diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h
index 5a74974302..06ffb517bb 100644
--- a/indra/newview/llconversationview.h
+++ b/indra/newview/llconversationview.h
@@ -136,6 +136,7 @@ public:
virtual ~LLConversationViewParticipant( void );
bool hasSameValue(const LLUUID& uuid) { return (uuid == mUUID); }
+ /*virtual*/ void refresh();
void addToFolder(LLFolderViewFolder* folder);
void addToSession(const LLUUID& session_id);
diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp
index 5443afe60c..b8e6e81ee6 100644
--- a/indra/newview/lldirpicker.cpp
+++ b/indra/newview/lldirpicker.cpp
@@ -315,7 +315,7 @@ void LLDirPickerThread::run()
//static
void LLDirPickerThread::initClass()
{
- sMutex = new LLMutex(NULL);
+ sMutex = new LLMutex();
}
//static
diff --git a/indra/newview/llexternaleditor.cpp b/indra/newview/llexternaleditor.cpp
index df9c848cb8..776bbf78c2 100644
--- a/indra/newview/llexternaleditor.cpp
+++ b/indra/newview/llexternaleditor.cpp
@@ -31,6 +31,7 @@
#include "llui.h"
#include "llprocess.h"
#include "llsdutil.h"
+#include "llstring.h"
#include <boost/foreach.hpp>
// static
@@ -188,12 +189,12 @@ std::string LLExternalEditor::findCommand(
cmd = LLUI::sSettingGroups["config"]->getString(sSetting);
LL_INFOS() << "Using setting" << LL_ENDL;
}
- else // otherwise use the path specified by the environment variable
+ else // otherwise use the path specified by the environment variable
{
- char* env_var_val = getenv(env_var.c_str());
+ auto env_var_val(LLStringUtil::getoptenv(env_var));
if (env_var_val)
{
- cmd = env_var_val;
+ cmd = *env_var_val;
LL_INFOS() << "Using env var " << env_var << LL_ENDL;
}
}
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 0f22b6200f..b6fd70452e 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -101,6 +101,8 @@ LLFilePicker::LLFilePicker()
mOFN.lpfnHook = NULL;
mOFN.lpTemplateName = NULL;
mFilesW[0] = '\0';
+#elif LL_DARWIN
+ mPickOptions = 0;
#endif
}
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index c5561fe011..33099db1b9 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -812,7 +812,7 @@ bool LLFloaterAvatarPicker::isSelectBtnEnabled()
{
bool ret_val = visibleItemsSelected();
- if ( ret_val )
+ if ( ret_val && !isMinimized())
{
std::string acvtive_panel_name;
LLScrollListCtrl* list = NULL;
diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp
index b48ecc8f31..66198b3bf6 100644
--- a/indra/newview/llfloaterconversationpreview.cpp
+++ b/indra/newview/llfloaterconversationpreview.cpp
@@ -46,7 +46,7 @@ LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_i
mPageSize(gSavedSettings.getS32("ConversationHistoryPageSize")),
mAccountName(session_id[LL_FCP_ACCOUNT_NAME]),
mCompleteName(session_id[LL_FCP_COMPLETE_NAME]),
- mMutex(NULL),
+ mMutex(),
mShowHistory(false),
mMessages(NULL),
mHistoryThreadsBusy(false),
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 3cfa1133df..30d05ae287 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -269,6 +269,9 @@ BOOL LLFloaterIMContainer::postBuild()
// When display name option change, we need to reload all participant names
LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLFloaterIMContainer::processParticipantsStyleUpdate, this));
+ mParticipantRefreshTimer.setTimerExpirySec(0);
+ mParticipantRefreshTimer.start();
+
return TRUE;
}
@@ -420,14 +423,66 @@ void LLFloaterIMContainer::processParticipantsStyleUpdate()
void LLFloaterIMContainer::idle(void* user_data)
{
LLFloaterIMContainer* self = static_cast<LLFloaterIMContainer*>(user_data);
-
- // Update the distance to agent in the nearby chat session if required
- // Note: it makes no sense of course to update the distance in other session
- if (self->mConversationViewModel.getSorter().getSortOrderParticipants() == LLConversationFilter::SO_DISTANCE)
- {
- self->setNearbyDistances();
- }
- self->mConversationsRoot->update();
+
+ if (!self->getVisible() || self->isMinimized())
+ {
+ return;
+ }
+ self->idleUpdate();
+}
+
+void LLFloaterIMContainer::idleUpdate()
+{
+ if (mTabContainer->getTabCount() == 0)
+ {
+ // Do not close the container when every conversation is torn off because the user
+ // still needs the conversation list. Simply collapse the message pane in that case.
+ collapseMessagesPane(true);
+ }
+
+ U32 sort_order = mConversationViewModel.getSorter().getSortOrderParticipants();
+
+ if (mParticipantRefreshTimer.hasExpired())
+ {
+ const LLConversationItem *current_session = getCurSelectedViewModelItem();
+ if (current_session)
+ {
+ // Update moderator options visibility
+ LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = current_session->getChildrenBegin();
+ LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = current_session->getChildrenEnd();
+ bool is_moderator = isGroupModerator();
+ bool can_ban = haveAbilityToBan();
+ while (current_participant_model != end_participant_model)
+ {
+ LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model);
+ participant_model->setModeratorOptionsVisible(is_moderator && participant_model->getUUID() != gAgentID);
+ participant_model->setGroupBanVisible(can_ban && participant_model->getUUID() != gAgentID);
+
+ current_participant_model++;
+ }
+ // Update floater's title as required by the currently selected session or use the default title
+ LLFloaterIMSession * conversation_floaterp = LLFloaterIMSession::findInstance(current_session->getUUID());
+ setTitle(conversation_floaterp && conversation_floaterp->needsTitleOverwrite() ? conversation_floaterp->getTitle() : mGeneralTitle);
+ }
+
+ mParticipantRefreshTimer.setTimerExpirySec(1.0f);
+ }
+
+ // Update the distance to agent in the nearby chat session if required
+ // Note: it makes no sense of course to update the distance in other session
+ if (sort_order == LLConversationFilter::SO_DISTANCE)
+ {
+ // almost real-time updates
+ setNearbyDistances(); //calls arrange all
+ }
+ mConversationsRoot->update(); //arranges, resizes, heavy
+
+ // "Manually" resize of mConversationsPane: same as temporarity cancellation of the flag "auto_resize=false" for it
+ if (!mConversationsPane->isCollapsed() && mMessagesPane->isCollapsed())
+ {
+ LLRect stack_rect = mConversationsStack->getRect();
+ mConversationsPane->reshape(stack_rect.getWidth(), stack_rect.getHeight(), true);
+ }
}
bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event)
@@ -526,39 +581,6 @@ bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event)
void LLFloaterIMContainer::draw()
{
- if (mTabContainer->getTabCount() == 0)
- {
- // Do not close the container when every conversation is torn off because the user
- // still needs the conversation list. Simply collapse the message pane in that case.
- collapseMessagesPane(true);
- }
-
- const LLConversationItem *current_session = getCurSelectedViewModelItem();
- if (current_session)
- {
- // Update moderator options visibility
- LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = current_session->getChildrenBegin();
- LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = current_session->getChildrenEnd();
- while (current_participant_model != end_participant_model)
- {
- LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model);
- participant_model->setModeratorOptionsVisible(isGroupModerator() && participant_model->getUUID() != gAgentID);
- participant_model->setGroupBanVisible(haveAbilityToBan() && participant_model->getUUID() != gAgentID);
-
- current_participant_model++;
- }
- // Update floater's title as required by the currently selected session or use the default title
- LLFloaterIMSession * conversation_floaterp = LLFloaterIMSession::findInstance(current_session->getUUID());
- setTitle(conversation_floaterp && conversation_floaterp->needsTitleOverwrite() ? conversation_floaterp->getTitle() : mGeneralTitle);
- }
-
- // "Manually" resize of mConversationsPane: same as temporarity cancellation of the flag "auto_resize=false" for it
- if (!mConversationsPane->isCollapsed() && mMessagesPane->isCollapsed())
- {
- LLRect stack_rect = mConversationsStack->getRect();
- mConversationsPane->reshape(stack_rect.getWidth(), stack_rect.getHeight(), true);
- }
-
LLFloater::draw();
}
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index 90fc0c2bdd..78b3572111 100644
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -180,6 +180,8 @@ private:
void openNearbyChat();
bool isParticipantListExpanded();
+ void idleUpdate(); // for convenience (self) from static idle
+
LLButton* mExpandCollapseBtn;
LLButton* mStubCollapseBtn;
LLButton* mSpeakBtn;
@@ -226,6 +228,8 @@ private:
LLConversationViewModel mConversationViewModel;
LLFolderView* mConversationsRoot;
LLEventStream mConversationsEventStream;
+
+ LLTimer mParticipantRefreshTimer;
};
#endif // LL_LLFLOATERIMCONTAINER_H
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index 88b3fb7b96..a462f391ca 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -415,6 +415,7 @@ BOOL LLPanelLandGeneral::postBuild()
mTextSalePending = getChild<LLTextBox>("SalePending");
mTextOwnerLabel = getChild<LLTextBox>("Owner:");
mTextOwner = getChild<LLTextBox>("OwnerText");
+ mTextOwner->setIsFriendCallback(LLAvatarActions::isFriend);
mContentRating = getChild<LLTextBox>("ContentRatingText");
mLandType = getChild<LLTextBox>("LandTypeText");
@@ -1191,6 +1192,7 @@ BOOL LLPanelLandObjects::postBuild()
mIconGroup = LLUIImageList::getInstance()->getUIImage("icon_group.tga", 0);
mOwnerList = getChild<LLNameListCtrl>("owner list");
+ mOwnerList->setIsFriendCallback(LLAvatarActions::isFriend);
mOwnerList->sortByColumnIndex(3, FALSE);
childSetCommitCallback("owner list", onCommitList, this);
mOwnerList->setDoubleClickCallback(onDoubleClickOwner, this);
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 268c646719..4f1ea4a89e 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -266,7 +266,7 @@ mCalculateBtn(NULL)
sInstance = this;
mLastMouseX = 0;
mLastMouseY = 0;
- mStatusLock = new LLMutex(NULL);
+ mStatusLock = new LLMutex();
mModelPreview = NULL;
mLODMode[LLModel::LOD_HIGH] = 0;
@@ -1208,7 +1208,7 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl
//-----------------------------------------------------------------------------
LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
-: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL)
+: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex()
, mLodsQuery()
, mLodsWithParsingError()
, mPelvisZOffset( 0.0f )
@@ -1418,8 +1418,6 @@ void LLModelPreview::rebuildUploadData()
std::string requested_name = mFMP->getChild<LLUICtrl>("description_form")->getValue().asString();
- std::string metric = mFMP->getChild<LLUICtrl>("model_category_combo")->getValue().asString();
-
LLSpinCtrl* scale_spinner = mFMP->getChild<LLSpinCtrl>("import_scale");
F32 scale = scale_spinner->getValue().asReal();
@@ -1460,7 +1458,6 @@ void LLModelPreview::rebuildUploadData()
if (base_model && !requested_name.empty())
{
base_model->mRequestedLabel = requested_name;
- base_model->mMetric = metric;
}
for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--)
diff --git a/indra/newview/llfloatermyscripts.cpp b/indra/newview/llfloatermyscripts.cpp
new file mode 100644
index 0000000000..fa2de21a8f
--- /dev/null
+++ b/indra/newview/llfloatermyscripts.cpp
@@ -0,0 +1,294 @@
+/**
+ * @file llfloatermyscripts.cpp
+ * @brief LLFloaterMyScripts class implementation.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2019, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llfloatermyscripts.h"
+
+#include "llagent.h"
+#include "llcorehttputil.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llfloaterreg.h"
+#include "llscrolllistctrl.h"
+#include "lltrans.h"
+#include "llviewerregion.h"
+
+const S32 SIZE_OF_ONE_KB = 1024;
+
+LLFloaterMyScripts::LLFloaterMyScripts(const LLSD& seed)
+ : LLFloater(seed),
+ mGotAttachmentMemoryUsed(false),
+ mAttachmentMemoryMax(0),
+ mAttachmentMemoryUsed(0),
+ mGotAttachmentURLsUsed(false),
+ mAttachmentURLsMax(0),
+ mAttachmentURLsUsed(0)
+{
+}
+
+BOOL LLFloaterMyScripts::postBuild()
+{
+ childSetAction("refresh_list_btn", onClickRefresh, this);
+
+ std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting");
+ getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_waiting));
+ return requestAttachmentDetails();
+}
+
+BOOL LLFloaterMyScripts::requestAttachmentDetails()
+{
+ if (!gAgent.getRegion()) return FALSE;
+
+ LLSD body;
+ std::string url = gAgent.getRegion()->getCapability("AttachmentResources");
+ if (!url.empty())
+ {
+ LLCoros::instance().launch("LLFloaterMyScripts::getAttachmentLimitsCoro",
+ boost::bind(&LLFloaterMyScripts::getAttachmentLimitsCoro, this, url));
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+void LLFloaterMyScripts::getAttachmentLimitsCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getAttachmentLimitsCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS() << "Unable to retrieve attachment limits." << LL_ENDL;
+ return;
+ }
+
+ LLFloaterMyScripts* instance = LLFloaterReg::getTypedInstance<LLFloaterMyScripts>("my_scripts");
+
+ if (!instance)
+ {
+ LL_WARNS() << "Failed to get LLFloaterMyScripts instance" << LL_ENDL;
+ return;
+ }
+
+ instance->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
+
+ LLButton* btn = instance->getChild<LLButton>("refresh_list_btn");
+ if (btn)
+ {
+ btn->setEnabled(true);
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ instance->setAttachmentDetails(result);
+}
+
+
+void LLFloaterMyScripts::setAttachmentDetails(LLSD content)
+{
+ LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list");
+
+ if(!list)
+ {
+ return;
+ }
+
+ S32 number_attachments = content["attachments"].size();
+
+ for(int i = 0; i < number_attachments; i++)
+ {
+ std::string humanReadableLocation = "";
+ if(content["attachments"][i].has("location"))
+ {
+ std::string actualLocation = content["attachments"][i]["location"];
+ humanReadableLocation = LLTrans::getString(actualLocation.c_str());
+ }
+
+ S32 number_objects = content["attachments"][i]["objects"].size();
+ for(int j = 0; j < number_objects; j++)
+ {
+ LLUUID task_id = content["attachments"][i]["objects"][j]["id"].asUUID();
+ S32 size = 0;
+ if(content["attachments"][i]["objects"][j]["resources"].has("memory"))
+ {
+ size = content["attachments"][i]["objects"][j]["resources"]["memory"].asInteger() / SIZE_OF_ONE_KB;
+ }
+ S32 urls = 0;
+ if(content["attachments"][i]["objects"][j]["resources"].has("urls"))
+ {
+ urls = content["attachments"][i]["objects"][j]["resources"]["urls"].asInteger();
+ }
+ std::string name = content["attachments"][i]["objects"][j]["name"].asString();
+
+ LLSD element;
+
+ element["id"] = task_id;
+ element["columns"][0]["column"] = "size";
+ element["columns"][0]["value"] = llformat("%d", size);
+ element["columns"][0]["font"] = "SANSSERIF";
+ element["columns"][0]["halign"] = LLFontGL::RIGHT;
+
+ element["columns"][1]["column"] = "urls";
+ element["columns"][1]["value"] = llformat("%d", urls);
+ element["columns"][1]["font"] = "SANSSERIF";
+ element["columns"][1]["halign"] = LLFontGL::RIGHT;
+
+ element["columns"][2]["column"] = "name";
+ element["columns"][2]["value"] = name;
+ element["columns"][2]["font"] = "SANSSERIF";
+
+ element["columns"][3]["column"] = "location";
+ element["columns"][3]["value"] = humanReadableLocation;
+ element["columns"][3]["font"] = "SANSSERIF";
+
+ list->addElement(element);
+ }
+ }
+
+ setAttachmentSummary(content);
+
+ getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
+
+ LLButton* btn = getChild<LLButton>("refresh_list_btn");
+ if(btn)
+ {
+ btn->setEnabled(true);
+ }
+}
+
+void LLFloaterMyScripts::clearList()
+{
+ LLCtrlListInterface *list = childGetListInterface("scripts_list");
+
+ if (list)
+ {
+ list->operateOnAll(LLCtrlListInterface::OP_DELETE);
+ }
+
+ std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting");
+ getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_waiting));
+}
+
+void LLFloaterMyScripts::setAttachmentSummary(LLSD content)
+{
+ if(content["summary"]["used"][0]["type"].asString() == std::string("memory"))
+ {
+ mAttachmentMemoryUsed = content["summary"]["used"][0]["amount"].asInteger() / SIZE_OF_ONE_KB;
+ mAttachmentMemoryMax = content["summary"]["available"][0]["amount"].asInteger() / SIZE_OF_ONE_KB;
+ mGotAttachmentMemoryUsed = true;
+ }
+ else if(content["summary"]["used"][1]["type"].asString() == std::string("memory"))
+ {
+ mAttachmentMemoryUsed = content["summary"]["used"][1]["amount"].asInteger() / SIZE_OF_ONE_KB;
+ mAttachmentMemoryMax = content["summary"]["available"][1]["amount"].asInteger() / SIZE_OF_ONE_KB;
+ mGotAttachmentMemoryUsed = true;
+ }
+ else
+ {
+ LL_WARNS() << "attachment details don't contain memory summary info" << LL_ENDL;
+ return;
+ }
+
+ if(content["summary"]["used"][0]["type"].asString() == std::string("urls"))
+ {
+ mAttachmentURLsUsed = content["summary"]["used"][0]["amount"].asInteger();
+ mAttachmentURLsMax = content["summary"]["available"][0]["amount"].asInteger();
+ mGotAttachmentURLsUsed = true;
+ }
+ else if(content["summary"]["used"][1]["type"].asString() == std::string("urls"))
+ {
+ mAttachmentURLsUsed = content["summary"]["used"][1]["amount"].asInteger();
+ mAttachmentURLsMax = content["summary"]["available"][1]["amount"].asInteger();
+ mGotAttachmentURLsUsed = true;
+ }
+ else
+ {
+ LL_WARNS() << "attachment details don't contain urls summary info" << LL_ENDL;
+ return;
+ }
+
+ if((mAttachmentMemoryUsed >= 0) && (mAttachmentMemoryMax >= 0))
+ {
+ LLStringUtil::format_map_t args_attachment_memory;
+ args_attachment_memory["[COUNT]"] = llformat ("%d", mAttachmentMemoryUsed);
+ std::string translate_message = "ScriptLimitsMemoryUsedSimple";
+
+ if (0 < mAttachmentMemoryMax)
+ {
+ S32 attachment_memory_available = mAttachmentMemoryMax - mAttachmentMemoryUsed;
+
+ args_attachment_memory["[MAX]"] = llformat ("%d", mAttachmentMemoryMax);
+ args_attachment_memory["[AVAILABLE]"] = llformat ("%d", attachment_memory_available);
+ translate_message = "ScriptLimitsMemoryUsed";
+ }
+
+ getChild<LLUICtrl>("memory_used")->setValue(LLTrans::getString(translate_message, args_attachment_memory));
+ }
+
+ if((mAttachmentURLsUsed >= 0) && (mAttachmentURLsMax >= 0))
+ {
+ S32 attachment_urls_available = mAttachmentURLsMax - mAttachmentURLsUsed;
+
+ LLStringUtil::format_map_t args_attachment_urls;
+ args_attachment_urls["[COUNT]"] = llformat ("%d", mAttachmentURLsUsed);
+ args_attachment_urls["[MAX]"] = llformat ("%d", mAttachmentURLsMax);
+ args_attachment_urls["[AVAILABLE]"] = llformat ("%d", attachment_urls_available);
+ std::string msg_attachment_urls = LLTrans::getString("ScriptLimitsURLsUsed", args_attachment_urls);
+ getChild<LLUICtrl>("urls_used")->setValue(LLSD(msg_attachment_urls));
+ }
+}
+
+// static
+void LLFloaterMyScripts::onClickRefresh(void* userdata)
+{
+ LLFloaterMyScripts* instance = LLFloaterReg::getTypedInstance<LLFloaterMyScripts>("my_scripts");
+ if(instance)
+ {
+ LLButton* btn = instance->getChild<LLButton>("refresh_list_btn");
+
+ //To stop people from hammering the refesh button and accidentally dosing themselves - enough requests can crash the viewer!
+ //turn the button off, then turn it on when we get a response
+ if(btn)
+ {
+ btn->setEnabled(false);
+ }
+ instance->clearList();
+ instance->requestAttachmentDetails();
+ }
+ else
+ {
+ LL_WARNS() << "could not find LLFloaterMyScripts instance after refresh button clicked" << LL_ENDL;
+ }
+}
+
diff --git a/indra/newview/llfloatermyscripts.h b/indra/newview/llfloatermyscripts.h
new file mode 100644
index 0000000000..fe33ab90ae
--- /dev/null
+++ b/indra/newview/llfloatermyscripts.h
@@ -0,0 +1,60 @@
+/**
+ * @file llfloatermyscripts.h
+ * @brief LLFloaterMyScripts class definition.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2019, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERMYSCRIPTS_H
+#define LL_LLFLOATERMYSCRIPTS_H
+
+#include "llfloater.h"
+#include "llpanel.h"
+
+class LLFloaterMyScripts : public LLFloater
+{
+public:
+ LLFloaterMyScripts(const LLSD& seed);
+
+ BOOL postBuild();
+ void setAttachmentDetails(LLSD content);
+ void setAttachmentSummary(LLSD content);
+ BOOL requestAttachmentDetails();
+ void clearList();
+
+private:
+ void getAttachmentLimitsCoro(std::string url);
+
+ bool mGotAttachmentMemoryUsed;
+ S32 mAttachmentMemoryMax;
+ S32 mAttachmentMemoryUsed;
+
+ bool mGotAttachmentURLsUsed;
+ S32 mAttachmentURLsMax;
+ S32 mAttachmentURLsUsed;
+
+protected:
+
+ static void onClickRefresh(void* userdata);
+};
+
+#endif
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index d63ee1b367..a3821ef21a 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -117,6 +117,8 @@
#include "llfeaturemanager.h"
#include "llviewertexturelist.h"
+#include "llsearchableui.h"
+
const F32 BANDWIDTH_UPDATER_TIMEOUT = 0.5f;
char const* const VISIBILITY_DEFAULT = "default";
char const* const VISIBILITY_HIDDEN = "hidden";
@@ -136,6 +138,25 @@ static const F32 MIN_ARC_LOG = log(MIN_ARC_LIMIT);
static const F32 MAX_ARC_LOG = log(MAX_ARC_LIMIT);
static const F32 ARC_LIMIT_MAP_SCALE = (MAX_ARC_LOG - MIN_ARC_LOG) / (MAX_INDIRECT_ARC_LIMIT - MIN_INDIRECT_ARC_LIMIT);
+struct LabelDef : public LLInitParam::Block<LabelDef>
+{
+ Mandatory<std::string> name;
+ Mandatory<std::string> value;
+
+ LabelDef()
+ : name("name"),
+ value("value")
+ {}
+};
+
+struct LabelTable : public LLInitParam::Block<LabelTable>
+{
+ Multiple<LabelDef> labels;
+ LabelTable()
+ : labels("label")
+ {}
+};
+
class LLVoiceSetKeyDialog : public LLModalDialog
{
public:
@@ -393,6 +414,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance()));
mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this));
+ mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // <FS:ND/> Hook up for filtering
}
void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType type )
@@ -506,7 +528,33 @@ BOOL LLFloaterPreference::postBuild()
LLSliderCtrl* fov_slider = getChild<LLSliderCtrl>("camera_fov");
fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView());
fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView());
-
+
+ // Hook up and init for filtering
+ mFilterEdit = getChild<LLSearchEditor>("search_prefs_edit");
+ mFilterEdit->setKeystrokeCallback(boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false));
+
+ // Load and assign label for 'default language'
+ std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "default_languages.xml");
+ std::map<std::string, std::string> labels;
+ if (loadFromFilename(user_filename, labels))
+ {
+ std::string system_lang = gSavedSettings.getString("SystemLanguage");
+ std::map<std::string, std::string>::iterator iter = labels.find(system_lang);
+ if (iter != labels.end())
+ {
+ getChild<LLComboBox>("language_combobox")->add(iter->second, LLSD("default"), ADD_TOP, true);
+ }
+ else
+ {
+ LL_WARNS() << "Language \"" << system_lang << "\" is not in default_languages.xml" << LL_ENDL;
+ getChild<LLComboBox>("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true);
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Failed to load labels from " << user_filename << ". Using default." << LL_ENDL;
+ getChild<LLComboBox>("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true);
+ }
return TRUE;
}
@@ -786,6 +834,13 @@ void LLFloaterPreference::onOpen(const LLSD& key)
save_btn->setEnabled(started);
delete_btn->setEnabled(started);
exceptions_btn->setEnabled(started);
+
+ collectSearchableItems();
+ if (!mFilterEdit->getText().empty())
+ {
+ mFilterEdit->setText(LLStringExplicit(""));
+ onUpdateFilterTerm(true);
+ }
}
void LLFloaterPreference::onVertexShaderEnable()
@@ -1966,6 +2021,45 @@ void LLFloaterPreference::updateMaxComplexity()
getChild<LLTextBox>("IndirectMaxComplexityText"));
}
+bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map<std::string, std::string> &label_map)
+{
+ LLXMLNodePtr root;
+
+ if (!LLXMLNode::parseFile(filename, root, NULL))
+ {
+ LL_WARNS() << "Unable to parse file " << filename << LL_ENDL;
+ return false;
+ }
+
+ if (!root->hasName("labels"))
+ {
+ LL_WARNS() << filename << " is not a valid definition file" << LL_ENDL;
+ return false;
+ }
+
+ LabelTable params;
+ LLXUIParser parser;
+ parser.readXUI(root, params, filename);
+
+ if (params.validateBlock())
+ {
+ for (LLInitParam::ParamIterator<LabelDef>::const_iterator it = params.labels.begin();
+ it != params.labels.end();
+ ++it)
+ {
+ LabelDef label_entry = *it;
+ label_map[label_entry.name] = label_entry.value;
+ }
+ }
+ else
+ {
+ LL_WARNS() << filename << " failed to load" << LL_ENDL;
+ return false;
+ }
+
+ return true;
+}
+
void LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity()
{
// Called when the IndirectMaxComplexity control changes
@@ -2329,6 +2423,7 @@ BOOL LLPanelPreference::postBuild()
if (hasChild("mute_chb_label", TRUE))
{
getChild<LLTextBox>("mute_chb_label")->setShowCursorHand(false);
+ getChild<LLTextBox>("mute_chb_label")->setSoundFlags(LLView::MOUSE_UP);
getChild<LLTextBox>("mute_chb_label")->setClickedCallback(boost::bind(&toggleMuteWhenMinimized));
}
@@ -2452,6 +2547,11 @@ void LLPanelPreference::toggleMuteWhenMinimized()
{
std::string mute("MuteWhenMinimized");
gSavedSettings.setBOOL(mute, !gSavedSettings.getBOOL(mute));
+ LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+ if (instance)
+ {
+ instance->getChild<LLCheckBoxCtrl>("mute_when_minimized")->setBtnFocus();
+ }
}
void LLPanelPreference::cancel()
@@ -2600,6 +2700,11 @@ void LLPanelPreferenceGraphics::onPresetsListChange()
{
instance->saveSettings(); //make cancel work correctly after changing the preset
}
+ else
+ {
+ std::string dummy;
+ instance->saveGraphicsPreset(dummy);
+ }
}
void LLPanelPreferenceGraphics::setPresetText()
@@ -2974,3 +3079,109 @@ void LLFloaterPreferenceProxy::onChangeSocksSettings()
}
+void LLFloaterPreference::onUpdateFilterTerm(bool force)
+{
+ LLWString seachValue = utf8str_to_wstring( mFilterEdit->getValue() );
+ LLWStringUtil::toLower( seachValue );
+
+ if( !mSearchData || (mSearchData->mLastFilter == seachValue && !force))
+ return;
+
+ mSearchData->mLastFilter = seachValue;
+
+ if( !mSearchData->mRootTab )
+ return;
+
+ mSearchData->mRootTab->hightlightAndHide( seachValue );
+ LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" );
+ if( pRoot )
+ pRoot->selectFirstTab();
+}
+
+void collectChildren( LLView const *aView, ll::prefs::PanelDataPtr aParentPanel, ll::prefs::TabContainerDataPtr aParentTabContainer )
+{
+ if( !aView )
+ return;
+
+ llassert_always( aParentPanel || aParentTabContainer );
+
+ LLView::child_list_const_iter_t itr = aView->beginChild();
+ LLView::child_list_const_iter_t itrEnd = aView->endChild();
+
+ while( itr != itrEnd )
+ {
+ LLView *pView = *itr;
+ ll::prefs::PanelDataPtr pCurPanelData = aParentPanel;
+ ll::prefs::TabContainerDataPtr pCurTabContainer = aParentTabContainer;
+ if( !pView )
+ continue;
+ LLPanel const *pPanel = dynamic_cast< LLPanel const *>( pView );
+ LLTabContainer const *pTabContainer = dynamic_cast< LLTabContainer const *>( pView );
+ ll::ui::SearchableControl const *pSCtrl = dynamic_cast< ll::ui::SearchableControl const *>( pView );
+
+ if( pTabContainer )
+ {
+ pCurPanelData.reset();
+
+ pCurTabContainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData );
+ pCurTabContainer->mTabContainer = const_cast< LLTabContainer *>( pTabContainer );
+ pCurTabContainer->mLabel = pTabContainer->getLabel();
+ pCurTabContainer->mPanel = 0;
+
+ if( aParentPanel )
+ aParentPanel->mChildPanel.push_back( pCurTabContainer );
+ if( aParentTabContainer )
+ aParentTabContainer->mChildPanel.push_back( pCurTabContainer );
+ }
+ else if( pPanel )
+ {
+ pCurTabContainer.reset();
+
+ pCurPanelData = ll::prefs::PanelDataPtr( new ll::prefs::PanelData );
+ pCurPanelData->mPanel = pPanel;
+ pCurPanelData->mLabel = pPanel->getLabel();
+
+ llassert_always( aParentPanel || aParentTabContainer );
+
+ if( aParentTabContainer )
+ aParentTabContainer->mChildPanel.push_back( pCurPanelData );
+ else if( aParentPanel )
+ aParentPanel->mChildPanel.push_back( pCurPanelData );
+ }
+ else if( pSCtrl && pSCtrl->getSearchText().size() )
+ {
+ ll::prefs::SearchableItemPtr item = ll::prefs::SearchableItemPtr( new ll::prefs::SearchableItem() );
+ item->mView = pView;
+ item->mCtrl = pSCtrl;
+
+ item->mLabel = utf8str_to_wstring( pSCtrl->getSearchText() );
+ LLWStringUtil::toLower( item->mLabel );
+
+ llassert_always( aParentPanel || aParentTabContainer );
+
+ if( aParentPanel )
+ aParentPanel->mChildren.push_back( item );
+ if( aParentTabContainer )
+ aParentTabContainer->mChildren.push_back( item );
+ }
+ collectChildren( pView, pCurPanelData, pCurTabContainer );
+ ++itr;
+ }
+}
+
+void LLFloaterPreference::collectSearchableItems()
+{
+ mSearchData.reset( nullptr );
+ LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" );
+ if( mFilterEdit && pRoot )
+ {
+ mSearchData.reset(new ll::prefs::SearchData() );
+
+ ll::prefs::TabContainerDataPtr pRootTabcontainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData );
+ pRootTabcontainer->mTabContainer = pRoot;
+ pRootTabcontainer->mLabel = pRoot->getLabel();
+ mSearchData->mRootTab = pRootTabcontainer;
+
+ collectChildren( this, ll::prefs::PanelDataPtr(), pRootTabcontainer );
+ }
+}
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 4e51137df5..1b8229ada6 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -36,6 +36,7 @@
#include "llfloater.h"
#include "llavatarpropertiesprocessor.h"
#include "llconversationlog.h"
+#include "llsearcheditor.h"
class LLConversationLogObserver;
class LLPanelPreference;
@@ -47,6 +48,14 @@ class LLSliderCtrl;
class LLSD;
class LLTextBox;
+namespace ll
+{
+ namespace prefs
+ {
+ struct SearchData;
+ }
+}
+
typedef std::map<std::string, std::string> notifications_map;
typedef enum
@@ -189,6 +198,7 @@ private:
void onDeleteTranscriptsResponse(const LLSD& notification, const LLSD& response);
void updateDeleteTranscriptsButton();
void updateMaxComplexity();
+ static bool loadFromFilename(const std::string& filename, std::map<std::string, std::string> &label_map);
static std::string sSkin;
notifications_map mNotificationOptions;
@@ -205,6 +215,12 @@ private:
LLAvatarData mAvatarProperties;
std::string mSavedGraphicsPreset;
LOG_CLASS(LLFloaterPreference);
+
+ LLSearchEditor *mFilterEdit;
+ std::unique_ptr< ll::prefs::SearchData > mSearchData;
+
+ void onUpdateFilterTerm( bool force = false );
+ void collectSearchableItems();
};
class LLPanelPreference : public LLPanel
diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp
index 21df769d0c..3746b9b6c2 100644
--- a/indra/newview/llfloaterscriptlimits.cpp
+++ b/indra/newview/llfloaterscriptlimits.cpp
@@ -90,19 +90,6 @@ LLFloaterScriptLimits::LLFloaterScriptLimits(const LLSD& seed)
BOOL LLFloaterScriptLimits::postBuild()
{
- // a little cheap and cheerful - if there's an about land panel open default to showing parcel info,
- // otherwise default to showing attachments (avatar appearance)
- bool selectParcelPanel = false;
-
- LLFloaterLand* instance = LLFloaterReg::getTypedInstance<LLFloaterLand>("about_land");
- if(instance)
- {
- if(instance->isShown())
- {
- selectParcelPanel = true;
- }
- }
-
mTab = getChild<LLTabContainer>("scriptlimits_panels");
if(!mTab)
@@ -111,28 +98,12 @@ BOOL LLFloaterScriptLimits::postBuild()
return FALSE;
}
- // contruct the panels
+ // contruct the panel
LLPanelScriptLimitsRegionMemory* panel_memory = new LLPanelScriptLimitsRegionMemory;
mInfoPanels.push_back(panel_memory);
panel_memory->buildFromFile( "panel_script_limits_region_memory.xml");
mTab->addTabPanel(panel_memory);
-
- LLPanelScriptLimitsAttachment* panel_attachments = new LLPanelScriptLimitsAttachment;
- mInfoPanels.push_back(panel_attachments);
- panel_attachments->buildFromFile("panel_script_limits_my_avatar.xml");
- mTab->addTabPanel(panel_attachments);
-
-
- if(mInfoPanels.size() > 0)
- {
- mTab->selectTab(0);
- }
-
- if(!selectParcelPanel && (mInfoPanels.size() > 1))
- {
- mTab->selectTab(1);
- }
-
+ mTab->selectTab(0);
return TRUE;
}
@@ -969,269 +940,3 @@ void LLPanelScriptLimitsRegionMemory::onClickReturn(void* userdata)
}
}
-///----------------------------------------------------------------------------
-// Attachment Panel
-///----------------------------------------------------------------------------
-
-BOOL LLPanelScriptLimitsAttachment::requestAttachmentDetails()
-{
- if (!gAgent.getRegion()) return FALSE;
-
- LLSD body;
- std::string url = gAgent.getRegion()->getCapability("AttachmentResources");
- if (!url.empty())
- {
- LLCoros::instance().launch("LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro",
- boost::bind(&LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro, this, url));
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-
-void LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro(std::string url)
-{
- LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
- httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getAttachmentLimitsCoro", httpPolicy));
- LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
-
- LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
-
- LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
-
- if (!status)
- {
- LL_WARNS() << "Unable to retrieve attachment limits." << LL_ENDL;
- return;
- }
-
- LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits");
-
- if (!instance)
- {
- LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL;
- return;
- }
-
- LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
- if (!tab)
- {
- LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL;
- return;
- }
-
- LLPanelScriptLimitsAttachment* panel = (LLPanelScriptLimitsAttachment*)tab->getChild<LLPanel>("script_limits_my_avatar_panel");
- if (!panel)
- {
- LL_WARNS() << "Failed to get script_limits_my_avatar_panel" << LL_ENDL;
- return;
- }
-
- panel->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
-
- LLButton* btn = panel->getChild<LLButton>("refresh_list_btn");
- if (btn)
- {
- btn->setEnabled(true);
- }
-
- result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
- panel->setAttachmentDetails(result);
-}
-
-
-void LLPanelScriptLimitsAttachment::setAttachmentDetails(LLSD content)
-{
- LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list");
-
- if(!list)
- {
- return;
- }
-
- S32 number_attachments = content["attachments"].size();
-
- for(int i = 0; i < number_attachments; i++)
- {
- std::string humanReadableLocation = "";
- if(content["attachments"][i].has("location"))
- {
- std::string actualLocation = content["attachments"][i]["location"];
- humanReadableLocation = LLTrans::getString(actualLocation.c_str());
- }
-
- S32 number_objects = content["attachments"][i]["objects"].size();
- for(int j = 0; j < number_objects; j++)
- {
- LLUUID task_id = content["attachments"][i]["objects"][j]["id"].asUUID();
- S32 size = 0;
- if(content["attachments"][i]["objects"][j]["resources"].has("memory"))
- {
- size = content["attachments"][i]["objects"][j]["resources"]["memory"].asInteger() / SIZE_OF_ONE_KB;
- }
- S32 urls = 0;
- if(content["attachments"][i]["objects"][j]["resources"].has("urls"))
- {
- urls = content["attachments"][i]["objects"][j]["resources"]["urls"].asInteger();
- }
- std::string name = content["attachments"][i]["objects"][j]["name"].asString();
-
- LLSD element;
-
- element["id"] = task_id;
- element["columns"][0]["column"] = "size";
- element["columns"][0]["value"] = llformat("%d", size);
- element["columns"][0]["font"] = "SANSSERIF";
- element["columns"][0]["halign"] = LLFontGL::RIGHT;
-
- element["columns"][1]["column"] = "urls";
- element["columns"][1]["value"] = llformat("%d", urls);
- element["columns"][1]["font"] = "SANSSERIF";
- element["columns"][1]["halign"] = LLFontGL::RIGHT;
-
- element["columns"][2]["column"] = "name";
- element["columns"][2]["value"] = name;
- element["columns"][2]["font"] = "SANSSERIF";
-
- element["columns"][3]["column"] = "location";
- element["columns"][3]["value"] = humanReadableLocation;
- element["columns"][3]["font"] = "SANSSERIF";
-
- list->addElement(element);
- }
- }
-
- setAttachmentSummary(content);
-
- getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
-
- LLButton* btn = getChild<LLButton>("refresh_list_btn");
- if(btn)
- {
- btn->setEnabled(true);
- }
-}
-
-BOOL LLPanelScriptLimitsAttachment::postBuild()
-{
- childSetAction("refresh_list_btn", onClickRefresh, this);
-
- std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting");
- getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_waiting));
- return requestAttachmentDetails();
-}
-
-void LLPanelScriptLimitsAttachment::clearList()
-{
- LLCtrlListInterface *list = childGetListInterface("scripts_list");
-
- if (list)
- {
- list->operateOnAll(LLCtrlListInterface::OP_DELETE);
- }
-
- std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting");
- getChild<LLUICtrl>("loading_text")->setValue(LLSD(msg_waiting));
-}
-
-void LLPanelScriptLimitsAttachment::setAttachmentSummary(LLSD content)
-{
- if(content["summary"]["used"][0]["type"].asString() == std::string("memory"))
- {
- mAttachmentMemoryUsed = content["summary"]["used"][0]["amount"].asInteger() / SIZE_OF_ONE_KB;
- mAttachmentMemoryMax = content["summary"]["available"][0]["amount"].asInteger() / SIZE_OF_ONE_KB;
- mGotAttachmentMemoryUsed = true;
- }
- else if(content["summary"]["used"][1]["type"].asString() == std::string("memory"))
- {
- mAttachmentMemoryUsed = content["summary"]["used"][1]["amount"].asInteger() / SIZE_OF_ONE_KB;
- mAttachmentMemoryMax = content["summary"]["available"][1]["amount"].asInteger() / SIZE_OF_ONE_KB;
- mGotAttachmentMemoryUsed = true;
- }
- else
- {
- LL_WARNS() << "attachment details don't contain memory summary info" << LL_ENDL;
- return;
- }
-
- if(content["summary"]["used"][0]["type"].asString() == std::string("urls"))
- {
- mAttachmentURLsUsed = content["summary"]["used"][0]["amount"].asInteger();
- mAttachmentURLsMax = content["summary"]["available"][0]["amount"].asInteger();
- mGotAttachmentURLsUsed = true;
- }
- else if(content["summary"]["used"][1]["type"].asString() == std::string("urls"))
- {
- mAttachmentURLsUsed = content["summary"]["used"][1]["amount"].asInteger();
- mAttachmentURLsMax = content["summary"]["available"][1]["amount"].asInteger();
- mGotAttachmentURLsUsed = true;
- }
- else
- {
- LL_WARNS() << "attachment details don't contain urls summary info" << LL_ENDL;
- return;
- }
-
- if((mAttachmentMemoryUsed >= 0) && (mAttachmentMemoryMax >= 0))
- {
- LLStringUtil::format_map_t args_attachment_memory;
- args_attachment_memory["[COUNT]"] = llformat ("%d", mAttachmentMemoryUsed);
- std::string translate_message = "ScriptLimitsMemoryUsedSimple";
-
- if (0 < mAttachmentMemoryMax)
- {
- S32 attachment_memory_available = mAttachmentMemoryMax - mAttachmentMemoryUsed;
-
- args_attachment_memory["[MAX]"] = llformat ("%d", mAttachmentMemoryMax);
- args_attachment_memory["[AVAILABLE]"] = llformat ("%d", attachment_memory_available);
- translate_message = "ScriptLimitsMemoryUsed";
- }
-
- getChild<LLUICtrl>("memory_used")->setValue(LLTrans::getString(translate_message, args_attachment_memory));
- }
-
- if((mAttachmentURLsUsed >= 0) && (mAttachmentURLsMax >= 0))
- {
- S32 attachment_urls_available = mAttachmentURLsMax - mAttachmentURLsUsed;
-
- LLStringUtil::format_map_t args_attachment_urls;
- args_attachment_urls["[COUNT]"] = llformat ("%d", mAttachmentURLsUsed);
- args_attachment_urls["[MAX]"] = llformat ("%d", mAttachmentURLsMax);
- args_attachment_urls["[AVAILABLE]"] = llformat ("%d", attachment_urls_available);
- std::string msg_attachment_urls = LLTrans::getString("ScriptLimitsURLsUsed", args_attachment_urls);
- getChild<LLUICtrl>("urls_used")->setValue(LLSD(msg_attachment_urls));
- }
-}
-
-// static
-void LLPanelScriptLimitsAttachment::onClickRefresh(void* userdata)
-{
- LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits");
- if(instance)
- {
- LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
- LLPanelScriptLimitsAttachment* panel_attachments = (LLPanelScriptLimitsAttachment*)tab->getChild<LLPanel>("script_limits_my_avatar_panel");
- LLButton* btn = panel_attachments->getChild<LLButton>("refresh_list_btn");
-
- //To stop people from hammering the refesh button and accidentally dosing themselves - enough requests can crash the viewer!
- //turn the button off, then turn it on when we get a response
- if(btn)
- {
- btn->setEnabled(false);
- }
- panel_attachments->clearList();
- panel_attachments->requestAttachmentDetails();
-
- return;
- }
- else
- {
- LL_WARNS() << "could not find LLPanelScriptLimitsRegionMemory instance after refresh button clicked" << LL_ENDL;
- return;
- }
-}
-
diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h
index 16450c6527..d2192f9d01 100644
--- a/indra/newview/llfloaterscriptlimits.h
+++ b/indra/newview/llfloaterscriptlimits.h
@@ -152,51 +152,4 @@ protected:
static void onClickReturn(void* userdata);
};
-/////////////////////////////////////////////////////////////////////////////
-// Attachment panel
-/////////////////////////////////////////////////////////////////////////////
-
-class LLPanelScriptLimitsAttachment : public LLPanelScriptLimitsInfo
-{
-
-public:
- LLPanelScriptLimitsAttachment()
- : LLPanelScriptLimitsInfo(),
- mGotAttachmentMemoryUsed(false),
- mAttachmentMemoryMax(0),
- mAttachmentMemoryUsed(0),
- mGotAttachmentURLsUsed(false),
- mAttachmentURLsMax(0),
- mAttachmentURLsUsed(0)
- {};
-
- ~LLPanelScriptLimitsAttachment()
- {
- };
-
- // LLPanel
- virtual BOOL postBuild();
-
- void setAttachmentDetails(LLSD content);
-
- void setAttachmentSummary(LLSD content);
- BOOL requestAttachmentDetails();
- void clearList();
-
-private:
- void getAttachmentLimitsCoro(std::string url);
-
- bool mGotAttachmentMemoryUsed;
- S32 mAttachmentMemoryMax;
- S32 mAttachmentMemoryUsed;
-
- bool mGotAttachmentURLsUsed;
- S32 mAttachmentURLsMax;
- S32 mAttachmentURLsUsed;
-
-protected:
-
- static void onClickRefresh(void* userdata);
-};
-
#endif
diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp
index 3e6fc3dc0d..bd49405f34 100644
--- a/indra/newview/llfloatertopobjects.cpp
+++ b/indra/newview/llfloatertopobjects.cpp
@@ -78,8 +78,6 @@ LLFloaterTopObjects::LLFloaterTopObjects(const LLSD& key)
mCommitCallbackRegistrar.add("TopObjects.ShowBeacon", boost::bind(&LLFloaterTopObjects::onClickShowBeacon, this));
mCommitCallbackRegistrar.add("TopObjects.ReturnSelected", boost::bind(&LLFloaterTopObjects::onReturnSelected, this));
mCommitCallbackRegistrar.add("TopObjects.ReturnAll", boost::bind(&LLFloaterTopObjects::onReturnAll, this));
- mCommitCallbackRegistrar.add("TopObjects.DisableSelected", boost::bind(&LLFloaterTopObjects::onDisableSelected, this));
- mCommitCallbackRegistrar.add("TopObjects.DisableAll", boost::bind(&LLFloaterTopObjects::onDisableAll, this));
mCommitCallbackRegistrar.add("TopObjects.Refresh", boost::bind(&LLFloaterTopObjects::onRefresh, this));
mCommitCallbackRegistrar.add("TopObjects.GetByObjectName", boost::bind(&LLFloaterTopObjects::onGetByObjectName, this));
mCommitCallbackRegistrar.add("TopObjects.GetByOwnerName", boost::bind(&LLFloaterTopObjects::onGetByOwnerName, this));
@@ -145,6 +143,7 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)
{
U32 request_flags;
U32 total_count;
+ U64 total_memory = 0;
msg->getU32Fast(_PREHASH_RequestData, _PREHASH_RequestFlags, request_flags);
msg->getU32Fast(_PREHASH_RequestData, _PREHASH_TotalObjectCount, total_count);
@@ -192,6 +191,7 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)
{
parcel_buf = parcel_name;
script_memory = script_size;
+ total_memory += script_size;
}
}
@@ -265,8 +265,10 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)
{
setTitle(getString("top_scripts_title"));
list->setColumnLabel("score", getString("scripts_score_label"));
-
+
LLUIString format = getString("top_scripts_text");
+ total_memory /= 1024;
+ format.setArg("[MEMORY]", llformat("%ld", total_memory));
format.setArg("[COUNT]", llformat("%d", total_count));
format.setArg("[TIME]", llformat("%0.3f", mtotalScore));
getChild<LLUICtrl>("title_text")->setValue(LLSD(format));
@@ -332,7 +334,7 @@ void LLFloaterTopObjects::onClickShowBeacon()
showBeacon();
}
-void LLFloaterTopObjects::doToObjects(int action, bool all)
+void LLFloaterTopObjects::returnObjects(bool all)
{
LLMessageSystem *msg = gMessageSystem;
@@ -356,14 +358,7 @@ void LLFloaterTopObjects::doToObjects(int action, bool all)
}
if (start_message)
{
- if (action == ACTION_RETURN)
- {
- msg->newMessageFast(_PREHASH_ParcelReturnObjects);
- }
- else
- {
- msg->newMessageFast(_PREHASH_ParcelDisableObjects);
- }
+ msg->newMessageFast(_PREHASH_ParcelReturnObjects);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
@@ -397,7 +392,7 @@ bool LLFloaterTopObjects::callbackReturnAll(const LLSD& notification, const LLSD
if(!instance) return false;
if (option == 0)
{
- instance->doToObjects(ACTION_RETURN, true);
+ instance->returnObjects(true);
}
return false;
}
@@ -410,31 +405,7 @@ void LLFloaterTopObjects::onReturnAll()
void LLFloaterTopObjects::onReturnSelected()
{
- doToObjects(ACTION_RETURN, false);
-}
-
-
-//static
-bool LLFloaterTopObjects::callbackDisableAll(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance<LLFloaterTopObjects>("top_objects");
- if(!instance) return false;
- if (option == 0)
- {
- instance->doToObjects(ACTION_DISABLE, true);
- }
- return false;
-}
-
-void LLFloaterTopObjects::onDisableAll()
-{
- LLNotificationsUtil::add("DisableAllTopObjects", LLSD(), LLSD(), callbackDisableAll);
-}
-
-void LLFloaterTopObjects::onDisableSelected()
-{
- doToObjects(ACTION_DISABLE, false);
+ returnObjects(false);
}
diff --git a/indra/newview/llfloatertopobjects.h b/indra/newview/llfloatertopobjects.h
index dbbe9ac521..3138249c7a 100644
--- a/indra/newview/llfloatertopobjects.h
+++ b/indra/newview/llfloatertopobjects.h
@@ -78,15 +78,12 @@ private:
static void onDoubleClickObjectsList(void* data);
void onClickShowBeacon();
- void doToObjects(int action, bool all);
+ void returnObjects(bool all);
void onReturnAll();
void onReturnSelected();
- void onDisableAll();
- void onDisableSelected();
static bool callbackReturnAll(const LLSD& notification, const LLSD& response);
- static bool callbackDisableAll(const LLSD& notification, const LLSD& response);
void onGetByOwnerName();
void onGetByObjectName();
@@ -108,12 +105,6 @@ private:
F32 mtotalScore;
- enum
- {
- ACTION_RETURN = 0,
- ACTION_DISABLE
- };
-
static LLFloaterTopObjects* sInstance;
};
diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp
index 76ad2146f1..db5a192287 100644
--- a/indra/newview/llfloateruipreview.cpp
+++ b/indra/newview/llfloateruipreview.cpp
@@ -60,6 +60,7 @@
#include "llfloaterreg.h"
#include "llscrollcontainer.h" // scroll container for overlapping elements
#include "lllivefile.h" // live file poll/stat/reload
+#include "llviewermenufile.h" // LLFilePickerReplyThread
// Boost (for linux/unix command-line execv)
#include <boost/tokenizer.hpp>
@@ -206,7 +207,9 @@ private:
void onClickSaveAll(S32 id);
void onClickEditFloater();
void onClickBrowseForEditor();
+ void getExecutablePath(const std::vector<std::string>& filenames);
void onClickBrowseForDiffs();
+ void getDiffsFilePath(const std::vector<std::string>& filenames);
void onClickToggleDiffHighlighting();
void onClickToggleOverlapping();
void onClickCloseDisplayedFloater(S32 id);
@@ -1019,15 +1022,14 @@ void LLFloaterUIPreview::onClickEditFloater()
// Respond to button click to browse for an executable with which to edit XML files
void LLFloaterUIPreview::onClickBrowseForEditor()
{
- // Let the user choose an executable through the file picker dialog box
- LLFilePicker& picker = LLFilePicker::instance();
- if (!picker.getOpenFile(LLFilePicker::FFLOAD_EXE))
- {
- return; // user cancelled -- do nothing
- }
+ // Let the user choose an executable through the file picker dialog box
+ (new LLFilePickerReplyThread(boost::bind(&LLFloaterUIPreview::getExecutablePath, this, _1), LLFilePicker::FFLOAD_EXE, false))->getFile();
+}
+void LLFloaterUIPreview::getExecutablePath(const std::vector<std::string>& filenames)
+{
// put the selected path into text field
- const std::string chosen_path = picker.getFirstFile();
+ const std::string chosen_path = filenames[0];
std::string executable_path = chosen_path;
#if LL_DARWIN
// on Mac, if it's an application bundle, figure out the actual path from the Info.plist file
@@ -1075,15 +1077,13 @@ void LLFloaterUIPreview::onClickBrowseForEditor()
void LLFloaterUIPreview::onClickBrowseForDiffs()
{
// create load dialog box
- LLFilePicker::ELoadFilter type = (LLFilePicker::ELoadFilter)((intptr_t)((void*)LLFilePicker::FFLOAD_XML)); // nothing for *.exe so just use all
- LLFilePicker& picker = LLFilePicker::instance();
- if (!picker.getOpenFile(type)) // user cancelled -- do nothing
- {
- return;
- }
+ (new LLFilePickerReplyThread(boost::bind(&LLFloaterUIPreview::getDiffsFilePath, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile();
+}
+void LLFloaterUIPreview::getDiffsFilePath(const std::vector<std::string>& filenames)
+{
// put the selected path into text field
- const std::string chosen_path = picker.getFirstFile();
+ const std::string chosen_path = filenames[0];
mDiffPathTextBox->setText(std::string(chosen_path)); // copy the path to the executable to the textfield for display and later fetching
if(LLView::sHighlightingDiffs) // if we're already highlighting, toggle off and then on so we get the data from the new file
{
diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index e76b3d118e..d59c301210 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -854,15 +854,33 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
}
else // IM_TASK_INVENTORY_OFFERED
{
- if (sizeof(S8) != binary_bucket_size)
+ if (offline == IM_OFFLINE && session_id.isNull() && aux_id.notNull() && binary_bucket_size > sizeof(S8)* 5)
{
- LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL;
- delete info;
- break;
+ // cap received offline message
+ std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size);
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
+ tokenizer tokens(str_bucket, sep);
+ tokenizer::iterator iter = tokens.begin();
+
+ info->mType = (LLAssetType::EType)(atoi((*(iter++)).c_str()));
+ // Note There is more elements in 'tokens' ...
+
+ info->mObjectID = LLUUID::null;
+ info->mFromObject = TRUE;
+ }
+ else
+ {
+ if (sizeof(S8) != binary_bucket_size)
+ {
+ LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL;
+ delete info;
+ break;
+ }
+ info->mType = (LLAssetType::EType) binary_bucket[0];
+ info->mObjectID = LLUUID::null;
+ info->mFromObject = TRUE;
}
- info->mType = (LLAssetType::EType) binary_bucket[0];
- info->mObjectID = LLUUID::null;
- info->mFromObject = TRUE;
}
info->mIM = dialog;
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 1987e15850..00b7732ee9 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -1415,7 +1415,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
break;
default:
- LL_INFOS() << "Unhandled asset type (llassetstorage.h): "
+ LL_INFOS_ONCE() << "Unhandled asset type (llassetstorage.h): "
<< (S32)asset_type << " (" << LLAssetType::lookup(asset_type) << ")" << LL_ENDL;
break;
}
@@ -7344,7 +7344,10 @@ void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_dequ
{
if (!LLAppearanceMgr::instance().canAddWearables(ids) && canWearSelected(ids))
{
- disabled_items.push_back(std::string("Wearable Add"));
+ disabled_items.push_back(std::string("Wearable And Object Wear"));
+ disabled_items.push_back(std::string("Wearable Add"));
+ disabled_items.push_back(std::string("Attach To"));
+ disabled_items.push_back(std::string("Attach To HUD"));
}
}
disable_context_entries_if_present(menu, disabled_items);
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index a520e0171e..b140c7c38e 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -1820,9 +1820,19 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item)
if (LLAssetType::lookup(item->getType()) == LLAssetType::badLookup())
{
- LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName()
- << " type: " << item->getType()
- << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL;
+ if (item->getType() >= LLAssetType::AT_COUNT)
+ {
+ // Not yet supported.
+ LL_DEBUGS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName()
+ << " type: " << item->getType()
+ << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName()
+ << " type: " << item->getType()
+ << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL;
+ }
}
// This condition means that we tried to add a link without the baseobj being in memory.
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 3992b506e9..d4993a1091 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -871,7 +871,8 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id)
if (objectp->getType() >= LLAssetType::AT_COUNT)
{
- LL_WARNS() << "LLInventoryPanel::buildNewViews called with unknown objectp->mType : "
+ // Example: Happens when we add assets of new, not yet supported type to library
+ LL_DEBUGS() << "LLInventoryPanel::buildNewViews called with unknown objectp->mType : "
<< ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
<< LL_ENDL;
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index c535fc1cdf..1bdeddbcfe 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -516,7 +516,7 @@ LLMutex* LLLogChat::historyThreadsMutex()
{
if (sHistoryThreadsMutex == NULL)
{
- sHistoryThreadsMutex = new LLMutex(NULL);
+ sHistoryThreadsMutex = new LLMutex();
}
return sHistoryThreadsMutex;
}
@@ -573,40 +573,10 @@ void LLLogChat::findTranscriptFiles(std::string pattern, std::vector<std::string
while (iter.next(filename))
{
std::string fullname = gDirUtilp->add(dirname, filename);
-
- LLFILE * filep = LLFile::fopen(fullname, "rb");
- if (NULL != filep)
+ if (isTranscriptFileFound(fullname))
{
- if(makeLogFileName("chat")== fullname)
- {
- //Add Nearby chat history to the list of transcriptions
- list_of_transcriptions.push_back(gDirUtilp->add(dirname, filename));
- LLFile::close(filep);
- continue;
- }
- char buffer[LOG_RECALL_SIZE];
-
- fseek(filep, 0, SEEK_END); // seek to end of file
- S32 bytes_to_read = ftell(filep); // get current file pointer
- fseek(filep, 0, SEEK_SET); // seek back to beginning of file
-
- // limit the number characters to read from file
- if (bytes_to_read >= LOG_RECALL_SIZE)
- {
- bytes_to_read = LOG_RECALL_SIZE - 1;
- }
-
- if (bytes_to_read > 0 && NULL != fgets(buffer, bytes_to_read, filep))
- {
- //matching a timestamp
- boost::match_results<std::string::const_iterator> matches;
- if (boost::regex_match(std::string(buffer), matches, TIMESTAMP))
- {
- list_of_transcriptions.push_back(gDirUtilp->add(dirname, filename));
- }
- }
- LLFile::close(filep);
- }
+ list_of_transcriptions.push_back(fullname);
+ }
}
}
@@ -756,75 +726,70 @@ void LLLogChat::deleteTranscripts()
// static
bool LLLogChat::isTranscriptExist(const LLUUID& avatar_id, bool is_group)
{
- std::vector<std::string> list_of_transcriptions;
- LLLogChat::getListOfTranscriptFiles(list_of_transcriptions);
-
- if (list_of_transcriptions.size() > 0)
+ LLAvatarName avatar_name;
+ LLAvatarNameCache::get(avatar_id, &avatar_name);
+ std::string avatar_user_name = avatar_name.getAccountName();
+ if(!is_group)
{
- LLAvatarName avatar_name;
- LLAvatarNameCache::get(avatar_id, &avatar_name);
- std::string avatar_user_name = avatar_name.getAccountName();
- if(!is_group)
- {
- std::replace(avatar_user_name.begin(), avatar_user_name.end(), '.', '_');
- BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
- {
- if (std::string::npos != transcript_file_name.find(avatar_user_name))
- {
- return true;
- }
- }
- }
- else
- {
- std::string file_name;
- gCacheName->getGroupName(avatar_id, file_name);
- file_name = makeLogFileName(file_name);
- BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
- {
- if (transcript_file_name == file_name)
- {
- return true;
- }
- }
- }
-
+ std::replace(avatar_user_name.begin(), avatar_user_name.end(), '.', '_');
+ return isTranscriptFileFound(makeLogFileName(avatar_user_name));
+ }
+ else
+ {
+ std::string file_name;
+ gCacheName->getGroupName(avatar_id, file_name);
+ file_name = makeLogFileName(file_name);
+ return isTranscriptFileFound(makeLogFileName(file_name));
}
-
return false;
}
bool LLLogChat::isNearbyTranscriptExist()
{
- std::vector<std::string> list_of_transcriptions;
- LLLogChat::getListOfTranscriptFiles(list_of_transcriptions);
-
- std::string file_name;
- file_name = makeLogFileName("chat");
- BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
- {
- if (transcript_file_name == file_name)
- {
- return true;
- }
- }
- return false;
+ return isTranscriptFileFound(makeLogFileName("chat"));;
}
bool LLLogChat::isAdHocTranscriptExist(std::string file_name)
{
- std::vector<std::string> list_of_transcriptions;
- LLLogChat::getListOfTranscriptFiles(list_of_transcriptions);
+ return isTranscriptFileFound(makeLogFileName(file_name));;
+}
- file_name = makeLogFileName(file_name);
- BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
+// static
+bool LLLogChat::isTranscriptFileFound(std::string fullname)
+{
+ bool result = false;
+ LLFILE * filep = LLFile::fopen(fullname, "rb");
+ if (NULL != filep)
{
- if (transcript_file_name == file_name)
- {
- return true;
+ if (makeLogFileName("chat") == fullname)
+ {
+ LLFile::close(filep);
+ return true;
+ }
+ char buffer[LOG_RECALL_SIZE];
+
+ fseek(filep, 0, SEEK_END); // seek to end of file
+ S32 bytes_to_read = ftell(filep); // get current file pointer
+ fseek(filep, 0, SEEK_SET); // seek back to beginning of file
+
+ // limit the number characters to read from file
+ if (bytes_to_read >= LOG_RECALL_SIZE)
+ {
+ bytes_to_read = LOG_RECALL_SIZE - 1;
}
+
+ if (bytes_to_read > 0 && NULL != fgets(buffer, bytes_to_read, filep))
+ {
+ //matching a timestamp
+ boost::match_results<std::string::const_iterator> matches;
+ if (boost::regex_match(std::string(buffer), matches, TIMESTAMP))
+ {
+ result = true;
+ }
+ }
+ LLFile::close(filep);
}
- return false;
+ return result;
}
//*TODO mark object's names in a special way so that they will be distinguishable form avatar name
@@ -1012,8 +977,8 @@ void LLDeleteHistoryThread::run()
LLActionThread::LLActionThread(const std::string& name)
: LLThread(name),
- mMutex(NULL),
- mRunCondition(NULL),
+ mMutex(),
+ mRunCondition(),
mFinished(false)
{
}
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index 6022e539a9..fcbd38a044 100644
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -121,6 +121,7 @@ public:
static bool isTranscriptExist(const LLUUID& avatar_id, bool is_group=false);
static bool isNearbyTranscriptExist();
static bool isAdHocTranscriptExist(std::string file_name);
+ static bool isTranscriptFileFound(std::string fullname);
static bool historyThreadsFinished(LLUUID session_id);
static LLLoadHistoryThread* getLoadHistoryThread(LLUUID session_id);
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index bc93fa2c20..08f41306b0 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -63,6 +63,9 @@
#include <sstream>
const S32 LOGIN_MAX_RETRIES = 3;
+const F32 LOGIN_SRV_TIMEOUT_MIN = 10;
+const F32 LOGIN_SRV_TIMEOUT_MAX = 120;
+const F32 LOGIN_DNS_TIMEOUT_FACTOR = 0.9; // make DNS wait shorter then retry time
class LLLoginInstance::Disposable {
public:
@@ -232,8 +235,10 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
// Specify desired timeout/retry options
LLSD http_params;
- http_params["timeout"] = gSavedSettings.getF32("LoginSRVTimeout");
+ F32 srv_timeout = llclamp(gSavedSettings.getF32("LoginSRVTimeout"), LOGIN_SRV_TIMEOUT_MIN, LOGIN_SRV_TIMEOUT_MAX);
+ http_params["timeout"] = srv_timeout;
http_params["retries"] = LOGIN_MAX_RETRIES;
+ http_params["DNSCacheTimeout"] = srv_timeout * LOGIN_DNS_TIMEOUT_FACTOR; //Default: indefinite
mRequestData.clear();
mRequestData["method"] = "login_to_simulator";
@@ -253,14 +258,12 @@ bool LLLoginInstance::handleLoginEvent(const LLSD& event)
mLoginState = event["state"].asString();
mResponseData = event["data"];
-
+
if(event.has("transfer_rate"))
{
mTransferRate = event["transfer_rate"].asReal();
}
-
-
// Call the method registered in constructor, if any, for more specific
// handling
mDispatcher.try_call(event);
@@ -276,6 +279,14 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
// Login has failed.
// Figure out why and respond...
LLSD response = event["data"];
+ LLSD updater = response["updater"];
+
+ // Always provide a response to the updater, if in fact the updater
+ // contacted us, if in fact the ping contains a 'reply' key. Most code
+ // paths tell it not to proceed with updating.
+ ResponsePtr resp(std::make_shared<LLEventAPI::Response>
+ (LLSDMap("update", false), updater));
+
std::string reason_response = response["reason"].asString();
std::string message_response = response["message"].asString();
LL_DEBUGS("LLLogin") << "reason " << reason_response
@@ -328,17 +339,44 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
}
else if(reason_response == "update")
{
- // This shouldn't happen - the viewer manager should have forced an update;
- // possibly the user ran the viewer directly and bypassed the update check
+ // This can happen if the user clicked Login quickly, before we heard
+ // back from the Viewer Version Manager, but login failed because
+ // login.cgi is insisting on a required update. We were called with an
+ // event that bundles both the login.cgi 'response' and the
+ // synchronization event from the 'updater'.
std::string required_version = response["message_args"]["VERSION"];
LL_WARNS("LLLogin") << "Login failed because an update to version " << required_version << " is required." << LL_ENDL;
if (gViewerWindow)
gViewerWindow->setShowProgress(FALSE);
- LLSD data(LLSD::emptyMap());
- data["VERSION"] = required_version;
- LLNotificationsUtil::add("RequiredUpdate", data, LLSD::emptyMap(), boost::bind(&LLLoginInstance::handleLoginDisallowed, this, _1, _2));
+ LLSD args(LLSDMap("VERSION", required_version));
+ if (updater.isUndefined())
+ {
+ // If the updater failed to shake hands, better advise the user to
+ // download the update him/herself.
+ LLNotificationsUtil::add(
+ "RequiredUpdate",
+ args,
+ updater,
+ boost::bind(&LLLoginInstance::handleLoginDisallowed, this, _1, _2));
+ }
+ else
+ {
+ // If we've heard from the updater that an update is required,
+ // then display the prompt that assures the user we'll take care
+ // of it. This is the one case in which we bind 'resp':
+ // instead of destroying our Response object (and thus sending a
+ // negative reply to the updater) as soon as we exit this
+ // function, bind our shared_ptr so it gets passed into
+ // syncWithUpdater. That ensures that the response is delayed
+ // until the user has responded to the notification.
+ LLNotificationsUtil::add(
+ "PauseForUpdate",
+ args,
+ updater,
+ boost::bind(&LLLoginInstance::syncWithUpdater, this, resp, _1, _2));
+ }
}
else if( reason_response == "key"
|| reason_response == "presence"
@@ -361,6 +399,19 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
}
}
+void LLLoginInstance::syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response)
+{
+ LL_INFOS("LLLogin") << "LLLoginInstance::syncWithUpdater" << LL_ENDL;
+ // 'resp' points to an instance of LLEventAPI::Response that will be
+ // destroyed as soon as we return and the notification response functor is
+ // unregistered. Modify it so that it tells the updater to go ahead and
+ // perform the update. Naturally, if we allowed the user a choice as to
+ // whether to proceed or not, this assignment would reflect the user's
+ // selection.
+ (*resp)["update"] = true;
+ attemptComplete();
+}
+
void LLLoginInstance::handleLoginDisallowed(const LLSD& notification, const LLSD& response)
{
attemptComplete();
@@ -420,7 +471,6 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
return true;
}
-
std::string construct_start_string()
{
std::string start;
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index 651ad10afb..b759b43474 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -28,8 +28,10 @@
#define LL_LLLOGININSTANCE_H
#include "lleventdispatcher.h"
+#include "lleventapi.h"
#include <boost/scoped_ptr.hpp>
#include <boost/function.hpp>
+#include <memory> // std::shared_ptr
#include "llsecapi.h"
class LLLogin;
class LLEventStream;
@@ -68,6 +70,7 @@ public:
LLNotificationsInterface& getNotificationsInterface() const { return *mNotifications; }
private:
+ typedef std::shared_ptr<LLEventAPI::Response> ResponsePtr;
void constructAuthParams(LLPointer<LLCredential> user_credentials);
void updateApp(bool mandatory, const std::string& message);
bool updateDialogCallback(const LLSD& notification, const LLSD& response);
@@ -77,7 +80,8 @@ private:
void handleLoginSuccess(const LLSD& event);
void handleDisconnect(const LLSD& event);
void handleIndeterminate(const LLSD& event);
- void handleLoginDisallowed(const LLSD& notification, const LLSD& response);
+ void handleLoginDisallowed(const LLSD& notification, const LLSD& response);
+ void syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response);
bool handleTOSResponse(bool v, const std::string& key);
diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp
index b0ee8e7fcb..2001359e50 100644
--- a/indra/newview/llmachineid.cpp
+++ b/indra/newview/llmachineid.cpp
@@ -65,11 +65,11 @@ public:
S32 LLMachineID::init()
{
- memset(static_unique_id,0,sizeof(static_unique_id));
+ size_t len = sizeof(static_unique_id);
+ memset(static_unique_id, 0, len);
S32 ret_code = 0;
#if LL_WINDOWS
# pragma comment(lib, "wbemuuid.lib")
- size_t len = sizeof(static_unique_id);
// algorithm to detect BIOS serial number found at:
// http://msdn.microsoft.com/en-us/library/aa394077%28VS.85%29.aspx
@@ -218,16 +218,19 @@ S32 LLMachineID::init()
// Get the value of the Name property
hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0);
LL_INFOS("AppInit") << " Serial Number : " << vtProp.bstrVal << LL_ENDL;
+
// use characters in the returned Serial Number to create a byte array of size len
BSTR serialNumber ( vtProp.bstrVal);
+ unsigned int serial_size = SysStringLen(serialNumber);
unsigned int j = 0;
- while( vtProp.bstrVal[j] != 0)
+
+ while (j < serial_size)
{
for (unsigned int i = 0; i < len; i++)
{
- if (vtProp.bstrVal[j] == 0)
+ if (j >= serial_size)
break;
-
+
static_unique_id[i] = (unsigned int)(static_unique_id[i] + serialNumber[j]);
j++;
}
@@ -254,16 +257,8 @@ S32 LLMachineID::init()
ret_code = LLUUID::getNodeID(staticPtr);
#endif
has_static_unique_id = true;
- return ret_code;
-}
-
-S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len)
-{
- if (has_static_unique_id)
- {
- memcpy ( unique_id, &static_unique_id, len);
- LL_INFOS_ONCE("AppInit") << "UniqueID: 0x";
+ LL_INFOS("AppInit") << "UniqueID: 0x";
// Code between here and LL_ENDL is not executed unless the LL_DEBUGS
// actually produces output
for (size_t i = 0; i < len; ++i)
@@ -271,11 +266,21 @@ S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len)
// Copy each char to unsigned int to hexify. Sending an unsigned
// char to a std::ostream tries to represent it as a char, not
// what we want here.
- unsigned byte = unique_id[i];
+ unsigned byte = static_unique_id[i];
LL_CONT << std::hex << std::setw(2) << std::setfill('0') << byte;
}
// Reset default output formatting to avoid nasty surprises!
LL_CONT << std::dec << std::setw(0) << std::setfill(' ') << LL_ENDL;
+
+ return ret_code;
+}
+
+
+S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len)
+{
+ if (has_static_unique_id)
+ {
+ memcpy ( unique_id, &static_unique_id, len);
return 1;
}
return 0;
diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp
index db8d2e4ede..6736e9a950 100644
--- a/indra/newview/llmainlooprepeater.cpp
+++ b/indra/newview/llmainlooprepeater.cpp
@@ -46,7 +46,7 @@ void LLMainLoopRepeater::start(void)
{
if(mQueue != 0) return;
- mQueue = new LLThreadSafeQueue<LLSD>(gAPRPoolp, 1024);
+ mQueue = new LLThreadSafeQueue<LLSD>(1024);
mMainLoopConnection = LLEventPumps::instance().
obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1));
mRepeaterConnection = LLEventPumps::instance().
diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp
index 8567180dd6..6589aa477f 100644
--- a/indra/newview/llmanip.cpp
+++ b/indra/newview/llmanip.cpp
@@ -431,7 +431,6 @@ void LLManip::renderXYZ(const LLVector3 &vec)
{
const S32 PAD = 10;
std::string feedback_string;
- LLVector3 camera_pos = LLViewerCamera::getInstance()->getOrigin() + LLViewerCamera::getInstance()->getAtAxis();
S32 window_center_x = gViewerWindow->getWorldViewRectScaled().getWidth() / 2;
S32 window_center_y = gViewerWindow->getWorldViewRectScaled().getHeight() / 2;
S32 vertical_offset = window_center_y - VERTICAL_OFFSET;
@@ -442,46 +441,55 @@ void LLManip::renderXYZ(const LLVector3 &vec)
LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square");
gViewerWindow->setup2DRender();
const LLVector2& display_scale = gViewerWindow->getDisplayScale();
- gGL.scalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
gGL.color4f(0.f, 0.f, 0.f, 0.7f);
imagep->draw(
- window_center_x - 115,
- window_center_y + vertical_offset - PAD,
- 235,
- PAD * 2 + 10,
+ (window_center_x - 115) * display_scale.mV[VX],
+ (window_center_y + vertical_offset - PAD) * display_scale.mV[VY],
+ 235 * display_scale.mV[VX],
+ (PAD * 2 + 10) * display_scale.mV[VY],
LLColor4(0.f, 0.f, 0.f, 0.7f) );
- }
- gGL.popMatrix();
-
- gViewerWindow->setup3DRender();
- {
- LLFontGL* font = LLFontGL::getFontSansSerif();
- LLLocale locale(LLLocale::USER_LOCALE);
- LLGLDepthTest gls_depth(GL_FALSE);
- // render drop shadowed text
- feedback_string = llformat("X: %.3f", vec.mV[VX]);
- hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -102.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE);
-
- feedback_string = llformat("Y: %.3f", vec.mV[VY]);
- hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -27.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE);
-
- feedback_string = llformat("Z: %.3f", vec.mV[VZ]);
- hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, 48.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE);
-
- // render text on top
- feedback_string = llformat("X: %.3f", vec.mV[VX]);
- hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -102.f, (F32)vertical_offset, LLColor4(1.f, 0.5f, 0.5f, 1.f), FALSE);
-
- gGL.diffuseColor3f(0.5f, 1.f, 0.5f);
- feedback_string = llformat("Y: %.3f", vec.mV[VY]);
- hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -27.f, (F32)vertical_offset, LLColor4(0.5f, 1.f, 0.5f, 1.f), FALSE);
-
- gGL.diffuseColor3f(0.5f, 0.5f, 1.f);
- feedback_string = llformat("Z: %.3f", vec.mV[VZ]);
- hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, 48.f, (F32)vertical_offset, LLColor4(0.5f, 0.5f, 1.f, 1.f), FALSE);
- }
+ LLFontGL* font = LLFontGL::getFontSansSerif();
+ LLLocale locale(LLLocale::USER_LOCALE);
+ LLGLDepthTest gls_depth(GL_FALSE);
+
+ // render drop shadowed text (manually because of bigger 'distance')
+ F32 right_x;
+ feedback_string = llformat("X: %.3f", vec.mV[VX]);
+ font->render(utf8str_to_wstring(feedback_string), 0, window_center_x - 102.f + 1.f, window_center_y + vertical_offset - 2.f, LLColor4::black,
+ LLFontGL::LEFT, LLFontGL::BASELINE,
+ LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x);
+
+ feedback_string = llformat("Y: %.3f", vec.mV[VY]);
+ font->render(utf8str_to_wstring(feedback_string), 0, window_center_x - 27.f + 1.f, window_center_y + vertical_offset - 2.f, LLColor4::black,
+ LLFontGL::LEFT, LLFontGL::BASELINE,
+ LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x);
+
+ feedback_string = llformat("Z: %.3f", vec.mV[VZ]);
+ font->render(utf8str_to_wstring(feedback_string), 0, window_center_x + 48.f + 1.f, window_center_y + vertical_offset - 2.f, LLColor4::black,
+ LLFontGL::LEFT, LLFontGL::BASELINE,
+ LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x);
+
+ // render text on top
+ feedback_string = llformat("X: %.3f", vec.mV[VX]);
+ font->render(utf8str_to_wstring(feedback_string), 0, window_center_x - 102.f, window_center_y + vertical_offset, LLColor4(1.f, 0.5f, 0.5f, 1.f),
+ LLFontGL::LEFT, LLFontGL::BASELINE,
+ LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x);
+
+ feedback_string = llformat("Y: %.3f", vec.mV[VY]);
+ font->render(utf8str_to_wstring(feedback_string), 0, window_center_x - 27.f, window_center_y + vertical_offset, LLColor4(0.5f, 1.f, 0.5f, 1.f),
+ LLFontGL::LEFT, LLFontGL::BASELINE,
+ LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x);
+
+ feedback_string = llformat("Z: %.3f", vec.mV[VZ]);
+ font->render(utf8str_to_wstring(feedback_string), 0, window_center_x + 48.f, window_center_y + vertical_offset, LLColor4(0.5f, 0.5f, 1.f, 1.f),
+ LLFontGL::LEFT, LLFontGL::BASELINE,
+ LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x);
+ }
+ gGL.popMatrix();
+
+ gViewerWindow->setup3DRender();
}
void LLManip::renderTickText(const LLVector3& pos, const std::string& text, const LLColor4 &color)
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index e38bd8846d..c4e7b17322 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -26,10 +26,11 @@
#include "llviewerprecompiledheaders.h"
+#include "llapr.h"
+#include "apr_portable.h"
#include "apr_pools.h"
#include "apr_dso.h"
#include "llhttpconstants.h"
-#include "llapr.h"
#include "llmeshrepository.h"
#include "llagent.h"
@@ -830,9 +831,9 @@ LLMeshRepoThread::LLMeshRepoThread()
{
LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
- mMutex = new LLMutex(NULL);
- mHeaderMutex = new LLMutex(NULL);
- mSignal = new LLCondition(NULL);
+ mMutex = new LLMutex();
+ mHeaderMutex = new LLMutex();
+ mSignal = new LLCondition();
mHttpRequest = new LLCore::HttpRequest;
mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
mHttpOptions->setTransferTimeout(SMALL_MESH_XFER_TIMEOUT);
@@ -1822,7 +1823,17 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat
return false;
}
- header_size += stream.tellg();
+ if (!header.isMap() || !header.has("version"))
+ {
+ LL_WARNS(LOG_MESH) << "Mesh header is invalid for ID: " << mesh_id << LL_ENDL;
+ return false;
+ }
+
+ // make sure there is at least one lod, function returns -1 and marks as 404 otherwise
+ if (LLMeshRepository::getActualMeshLOD(header, 0) >= 0)
+ {
+ header_size += stream.tellg();
+ }
}
else
{
@@ -2039,7 +2050,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
mUploadSkin = upload_skin;
mUploadJoints = upload_joints;
mLockScaleIfJointPosition = lock_scale_if_joint_position;
- mMutex = new LLMutex(NULL);
+ mMutex = new LLMutex();
mPendingUploads = 0;
mFinished = false;
mOrigin = gAgent.getPositionAgent();
@@ -2174,7 +2185,6 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
std::map<LLModel*,S32> mesh_index;
std::string model_name;
- std::string model_metric;
S32 instance_num = 0;
@@ -2204,11 +2214,6 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
model_name = data.mBaseModel->getName();
}
- if (model_metric.empty())
- {
- model_metric = data.mBaseModel->getMetric();
- }
-
std::stringstream ostr;
LLModel::Decomposition& decomp =
@@ -2363,11 +2368,6 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
model_name = data.mBaseModel->getName();
}
- if (model_metric.empty())
- {
- model_metric = data.mBaseModel->getMetric();
- }
-
std::stringstream ostr;
LLModel::Decomposition& decomp =
@@ -2498,8 +2498,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
if (model_name.empty()) model_name = "mesh model";
result["name"] = model_name;
- if (model_metric.empty()) model_metric = "MUT_Unspecified";
- res["metric"] = model_metric;
+ res["metric"] = "MUT_Unspecified";
result["asset_resources"] = res;
dump_llsd_to_file(result,make_dump_name("whole_model_",dump_num));
@@ -2919,9 +2918,14 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod)
{
lod = llclamp(lod, 0, 3);
+ if (header.has("404"))
+ {
+ return -1;
+ }
+
S32 version = header["version"];
- if (header.has("404") || version > MAX_MESH_VERSION)
+ if (version > MAX_MESH_VERSION)
{
return -1;
}
@@ -3458,7 +3462,7 @@ LLMeshRepository::LLMeshRepository()
void LLMeshRepository::init()
{
- mMeshMutex = new LLMutex(NULL);
+ mMeshMutex = new LLMutex();
LLConvexDecomposition::getInstance()->initSystem();
@@ -4302,10 +4306,13 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* byte
F32 dlow = llmin(radius/0.06f, max_distance);
F32 dmid = llmin(radius/0.24f, max_distance);
- F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead
- F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free"
+ static LLCachedControl<U32> metadata_discount_ch(gSavedSettings, "MeshMetaDataDiscount", 384); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead
+ static LLCachedControl<U32> minimum_size_ch(gSavedSettings, "MeshMinimumByteSize", 16); //make sure nothing is "free"
+ static LLCachedControl<U32> bytes_per_triangle_ch(gSavedSettings, "MeshBytesPerTriangle", 16);
- F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle");
+ F32 metadata_discount = (F32)metadata_discount_ch;
+ F32 minimum_size = (F32)minimum_size_ch;
+ F32 bytes_per_triangle = (F32)bytes_per_triangle_ch;
S32 bytes_lowest = header["lowest_lod"]["size"].asInteger();
S32 bytes_low = header["low_lod"]["size"].asInteger();
@@ -4332,10 +4339,10 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* byte
bytes_lowest = bytes_low;
}
- F32 triangles_lowest = llmax((F32) bytes_lowest-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
- F32 triangles_low = llmax((F32) bytes_low-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
- F32 triangles_mid = llmax((F32) bytes_mid-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
- F32 triangles_high = llmax((F32) bytes_high-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
+ F32 triangles_lowest = llmax((F32) bytes_lowest-metadata_discount, minimum_size)/bytes_per_triangle;
+ F32 triangles_low = llmax((F32) bytes_low-metadata_discount, minimum_size)/bytes_per_triangle;
+ F32 triangles_mid = llmax((F32) bytes_mid-metadata_discount, minimum_size)/bytes_per_triangle;
+ F32 triangles_high = llmax((F32) bytes_high-metadata_discount, minimum_size)/bytes_per_triangle;
if (bytes)
{
@@ -4429,13 +4436,13 @@ bool LLMeshCostData::init(const LLSD& header)
mSizeByLOD[2] = bytes_med;
mSizeByLOD[3] = bytes_high;
- F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead
- F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free"
- F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle");
+ static LLCachedControl<U32> metadata_discount(gSavedSettings, "MeshMetaDataDiscount", 384); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead
+ static LLCachedControl<U32> minimum_size(gSavedSettings, "MeshMinimumByteSize", 16); //make sure nothing is "free"
+ static LLCachedControl<U32> bytes_per_triangle(gSavedSettings, "MeshBytesPerTriangle", 16);
for (S32 i=0; i<4; i++)
{
- mEstTrisByLOD[i] = llmax((F32) mSizeByLOD[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
+ mEstTrisByLOD[i] = llmax((F32)mSizeByLOD[i] - (F32)metadata_discount, (F32)minimum_size) / (F32)bytes_per_triangle;
}
return true;
@@ -4597,8 +4604,8 @@ LLPhysicsDecomp::LLPhysicsDecomp()
mQuitting = false;
mDone = false;
- mSignal = new LLCondition(NULL);
- mMutex = new LLMutex(NULL);
+ mSignal = new LLCondition();
+ mMutex = new LLMutex();
}
LLPhysicsDecomp::~LLPhysicsDecomp()
diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp
index 301487b994..19f238d99a 100644
--- a/indra/newview/llmoveview.cpp
+++ b/indra/newview/llmoveview.cpp
@@ -702,11 +702,9 @@ void LLPanelStandStopFlying::updatePosition()
{
if (mAttached) return;
- S32 y_pos = 0;
S32 bottom_tb_center = 0;
if (LLToolBar* toolbar_bottom = gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_BOTTOM))
{
- y_pos = toolbar_bottom->getRect().getHeight();
bottom_tb_center = toolbar_bottom->getRect().getCenterX();
}
@@ -716,20 +714,6 @@ void LLPanelStandStopFlying::updatePosition()
left_tb_width = toolbar_left->getRect().getWidth();
}
- if (!mStateManagementButtons.get()) // Obsolete?!!
- {
- LLPanel* panel_ssf_container = gToolBarView->getChild<LLPanel>("state_management_buttons_container");
- if (panel_ssf_container)
- {
- mStateManagementButtons = panel_ssf_container->getHandle();
- }
- }
-
- if(LLPanel* panel_ssf_container = mStateManagementButtons.get())
- {
- panel_ssf_container->setOrigin(0, y_pos);
- }
-
if (gToolBarView != NULL && gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_LEFT)->hasButtons())
{
S32 x_pos = bottom_tb_center - getRect().getWidth() / 2 - left_tb_width;
diff --git a/indra/newview/llmoveview.h b/indra/newview/llmoveview.h
index 4a31f2a814..e8b9a6fdb2 100644
--- a/indra/newview/llmoveview.h
+++ b/indra/newview/llmoveview.h
@@ -172,8 +172,6 @@ private:
*/
LLHandle<LLPanel> mOriginalParent;
- LLHandle<LLPanel> mStateManagementButtons;
-
/**
* True if the panel is currently attached to the movement controls floater.
*
diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp
index a5bc75e6bd..b405d3dca2 100644
--- a/indra/newview/llnotificationlistitem.cpp
+++ b/indra/newview/llnotificationlistitem.cpp
@@ -135,7 +135,8 @@ std::string LLNotificationListItem::buildNotificationDate(const LLDate& time_sta
+LLTrans::getString("TimeDay")+"]/["
+LLTrans::getString("TimeYear")+"] ["
+LLTrans::getString("TimeHour")+"]:["
- +LLTrans::getString("TimeMin")+"]";
+ +LLTrans::getString("TimeMin")+"] ["
+ +LLTrans::getString("TimeTimezone")+"]";
break;
}
LLSD substitution;
@@ -376,13 +377,13 @@ BOOL LLGroupNoticeNotificationListItem::postBuild()
mTitleBoxExp->setValue(mParams.subject);
mNoticeTextExp->setValue(mParams.message);
- mTimeBox->setValue(buildNotificationDate(mParams.time_stamp, UTC));
- mTimeBoxExp->setValue(buildNotificationDate(mParams.time_stamp, UTC));
+ mTimeBox->setValue(buildNotificationDate(mParams.time_stamp));
+ mTimeBoxExp->setValue(buildNotificationDate(mParams.time_stamp));
//Workaround: in case server timestamp is 0 - we use the time when notification was actually received
if (mParams.time_stamp.isNull())
{
- mTimeBox->setValue(buildNotificationDate(mParams.received_time, UTC));
- mTimeBoxExp->setValue(buildNotificationDate(mParams.received_time, UTC));
+ mTimeBox->setValue(buildNotificationDate(mParams.received_time));
+ mTimeBoxExp->setValue(buildNotificationDate(mParams.received_time));
}
setSender(mParams.sender);
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 892fa385d7..f2a284a561 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -621,8 +621,14 @@ void LLOutfitsList::applyFilterToTab(
bool LLOutfitsList::canWearSelected()
{
+ if (!isAgentAvatarValid())
+ {
+ return false;
+ }
+
uuid_vec_t selected_items;
getSelectedItemsUUIDs(selected_items);
+ S32 nonreplacable_objects = 0;
for (uuid_vec_t::const_iterator it = selected_items.begin(); it != selected_items.end(); ++it)
{
@@ -633,10 +639,21 @@ bool LLOutfitsList::canWearSelected()
{
return false;
}
+
+ const LLViewerInventoryItem* item = gInventory.getItem(id);
+ if (!item)
+ {
+ return false;
+ }
+
+ if (item->getType() == LLAssetType::AT_OBJECT)
+ {
+ nonreplacable_objects++;
+ }
}
- // All selected items can be worn.
- return true;
+ // All selected items can be worn. But do we have enough space for them?
+ return nonreplacable_objects == 0 || gAgentAvatarp->canAttachMoreObjects(nonreplacable_objects);
}
void LLOutfitsList::wearSelectedItems()
diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp
index 6c26073d5b..c5e4593b79 100644
--- a/indra/newview/lloutputmonitorctrl.cpp
+++ b/indra/newview/lloutputmonitorctrl.cpp
@@ -72,6 +72,7 @@ LLOutputMonitorCtrl::LLOutputMonitorCtrl(const LLOutputMonitorCtrl::Params& p)
mImageLevel3(p.image_level_3),
mAutoUpdate(p.auto_update),
mSpeakerId(p.speaker_id),
+ mIsModeratorMuted(false),
mIsAgentControl(false),
mIndicatorToggled(false),
mShowParticipantsSpeaking(false)
@@ -124,7 +125,7 @@ void LLOutputMonitorCtrl::draw()
const F32 LEVEL_1 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL * 2.f / 3.f;
const F32 LEVEL_2 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL;
- if (getVisible() && mAutoUpdate && !mIsMuted && mSpeakerId.notNull())
+ if (getVisible() && mAutoUpdate && !getIsMuted() && mSpeakerId.notNull())
{
setPower(LLVoiceClient::getInstance()->getCurrentPower(mSpeakerId));
if(mIsAgentControl)
@@ -156,7 +157,7 @@ void LLOutputMonitorCtrl::draw()
}
LLPointer<LLUIImage> icon;
- if (mIsMuted)
+ if (getIsMuted())
{
icon = mImageMute;
}
diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h
index 0682af1278..af52a81b04 100644
--- a/indra/newview/lloutputmonitorctrl.h
+++ b/indra/newview/lloutputmonitorctrl.h
@@ -72,7 +72,10 @@ public:
void setPower(F32 val);
F32 getPower(F32 val) const { return mPower; }
-
+
+ bool getIsMuted() const { return (mIsMuted || mIsModeratorMuted); }
+ void setIsModeratorMuted(bool val) { mIsModeratorMuted = val; }
+
// For the current user, need to know the PTT state to show
// correct button image.
void setIsAgentControl(bool val) { mIsAgentControl = val; }
@@ -131,6 +134,7 @@ private:
F32 mPower;
bool mIsAgentControl;
+ bool mIsModeratorMuted;
bool mIsMuted;
bool mIsTalking;
bool mShowParticipantsSpeaking;
diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp
index b9b97f4cce..6d0c30fbf3 100644
--- a/indra/newview/llpanelclassified.cpp
+++ b/indra/newview/llpanelclassified.cpp
@@ -628,12 +628,9 @@ BOOL LLPanelClassifiedEdit::postBuild()
{
LLPanelClassifiedInfo::postBuild();
- LLTextureCtrl* snapshot = getChild<LLTextureCtrl>("classified_snapshot");
- snapshot->setOnSelectCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this));
-
LLUICtrl* edit_icon = getChild<LLUICtrl>("edit_icon");
- snapshot->setMouseEnterCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseEnter, this, edit_icon));
- snapshot->setMouseLeaveCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseLeave, this, edit_icon));
+ mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseEnter, this, edit_icon));
+ mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseLeave, this, edit_icon));
edit_icon->setVisible(false);
LLLineEditor* line_edit = getChild<LLLineEditor>("classified_name");
@@ -1130,6 +1127,7 @@ void LLPanelClassifiedEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl)
void LLPanelClassifiedEdit::onTextureSelected()
{
setSnapshotId(mSnapshotCtrl->getValue().asUUID());
+ onChange();
}
//////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 8d7865c8ba..2232589ec4 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -1384,6 +1384,11 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
mColorSwatch->setFallbackImage(LLUI::getUIImage("locked_image.j2c") );
mColorSwatch->setValid(FALSE);
}
+ LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
+ if (radio_mat_type)
+ {
+ radio_mat_type->setSelectedIndex(0);
+ }
getChildView("color trans")->setEnabled(FALSE);
getChildView("rptctrl")->setEnabled(FALSE);
getChildView("tex gen")->setEnabled(FALSE);
diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp
index f85a2ffbc1..b53cd222e7 100644
--- a/indra/newview/llpanelgroupgeneral.cpp
+++ b/indra/newview/llpanelgroupgeneral.cpp
@@ -461,11 +461,12 @@ bool LLPanelGroupGeneral::createGroupCallback(const LLSD& notification, const LL
// Yay! We are making a new group!
U32 enrollment_fee = (mCtrlEnrollmentFee->get() ?
(U32) mSpinEnrollmentFee->get() : 0);
-
+ LLUUID insignia_id = mInsignia->getImageItemID().isNull() ? LLUUID::null : mInsignia->getImageAssetID();
+
LLGroupMgr::getInstance()->sendCreateGroupRequest(mGroupNameEditor->getText(),
mEditCharter->getText(),
mCtrlShowInGroupList->get(),
- mInsignia->getImageAssetID(),
+ insignia_id,
enrollment_fee,
mCtrlOpenEnrollment->get(),
false,
diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h
index 46a6d0ef50..8908078c63 100644
--- a/indra/newview/llpreviewnotecard.h
+++ b/indra/newview/llpreviewnotecard.h
@@ -47,18 +47,18 @@ public:
virtual ~LLPreviewNotecard();
bool saveItem();
- void setObjectID(const LLUUID& object_id);
+ void setObjectID(const LLUUID& object_id) override;
// llview
- virtual void draw();
- virtual BOOL handleKeyHere(KEY key, MASK mask);
- virtual void setEnabled( BOOL enabled );
+ void draw() override;
+ BOOL handleKeyHere(KEY key, MASK mask) override;
+ void setEnabled( BOOL enabled ) override;
// llfloater
- virtual BOOL canClose();
+ BOOL canClose() override;
// llpanel
- virtual BOOL postBuild();
+ BOOL postBuild() override;
// reach into the text editor, and grab the drag item
const LLInventoryItem* getDragItem();
@@ -74,8 +74,8 @@ public:
protected:
- void updateTitleButtons();
- virtual void loadAsset();
+ void updateTitleButtons() override;
+ void loadAsset() override;
bool saveIfNeeded(LLInventoryItem* copyitem = NULL);
void deleteNotecard();
diff --git a/indra/newview/llsearchableui.cpp b/indra/newview/llsearchableui.cpp
new file mode 100644
index 0000000000..93143eb33f
--- /dev/null
+++ b/indra/newview/llsearchableui.cpp
@@ -0,0 +1,160 @@
+/**
+* @file llsearchableui.cpp
+*
+* $LicenseInfo:firstyear=2019&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2019, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#include "llviewerprecompiledheaders.h"
+#include "llsearchableui.h"
+
+#include "llview.h"
+#include "lltabcontainer.h"
+#include "llmenugl.h"
+
+ll::prefs::SearchableItem::~SearchableItem()
+{}
+
+void ll::prefs::SearchableItem::setNotHighlighted()
+{
+ mCtrl->setHighlighted( false );
+}
+
+bool ll::prefs::SearchableItem::hightlightAndHide( LLWString const &aFilter )
+{
+ if( mCtrl->getHighlighted() )
+ return true;
+
+ LLView const *pView = dynamic_cast< LLView const* >( mCtrl );
+ if( pView && !pView->getVisible() )
+ return false;
+
+ if( aFilter.empty() )
+ {
+ mCtrl->setHighlighted( false );
+ return true;
+ }
+
+ if( mLabel.find( aFilter ) != LLWString::npos )
+ {
+ mCtrl->setHighlighted( true );
+ return true;
+ }
+
+ return false;
+}
+
+ll::prefs::PanelData::~PanelData()
+{}
+
+bool ll::prefs::PanelData::hightlightAndHide( LLWString const &aFilter )
+{
+ for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr )
+ (*itr)->setNotHighlighted( );
+
+ if (aFilter.empty())
+ {
+ return true;
+ }
+
+ bool bVisible(false);
+ for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr )
+ bVisible |= (*itr)->hightlightAndHide( aFilter );
+
+ for( tPanelDataList::iterator itr = mChildPanel.begin(); itr != mChildPanel.end(); ++itr )
+ bVisible |= (*itr)->hightlightAndHide( aFilter );
+
+ return bVisible;
+}
+
+bool ll::prefs::TabContainerData::hightlightAndHide( LLWString const &aFilter )
+{
+ for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr )
+ (*itr)->setNotHighlighted( );
+
+ bool bVisible(false);
+ for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr )
+ bVisible |= (*itr)->hightlightAndHide( aFilter );
+
+ for( tPanelDataList::iterator itr = mChildPanel.begin(); itr != mChildPanel.end(); ++itr )
+ {
+ bool bPanelVisible = (*itr)->hightlightAndHide( aFilter );
+ if( (*itr)->mPanel )
+ mTabContainer->setTabVisibility( (*itr)->mPanel, bPanelVisible );
+ bVisible |= bPanelVisible;
+ }
+
+ return bVisible;
+}
+
+ll::statusbar::SearchableItem::SearchableItem()
+ : mMenu(0)
+ , mCtrl(0)
+ , mWasHiddenBySearch( false )
+{ }
+
+void ll::statusbar::SearchableItem::setNotHighlighted( )
+{
+ for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr )
+ (*itr)->setNotHighlighted( );
+
+ if( mCtrl )
+ {
+ mCtrl->setHighlighted( false );
+
+ if( mWasHiddenBySearch )
+ mMenu->setVisible( TRUE );
+ }
+}
+
+bool ll::statusbar::SearchableItem::hightlightAndHide(LLWString const &aFilter, bool hide)
+{
+ if ((mMenu && !mMenu->getVisible() && !mWasHiddenBySearch) || dynamic_cast<LLMenuItemTearOffGL*>(mMenu))
+ return false;
+
+ setNotHighlighted( );
+
+ if( aFilter.empty() )
+ {
+ if( mCtrl )
+ mCtrl->setHighlighted( false );
+ return true;
+ }
+
+ bool bHighlighted(!hide);
+ if( mLabel.find( aFilter ) != LLWString::npos )
+ {
+ if( mCtrl )
+ mCtrl->setHighlighted( true );
+ bHighlighted = true;
+ }
+
+ bool bVisible(false);
+ for (tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr)
+ bVisible |= (*itr)->hightlightAndHide(aFilter, !bHighlighted);
+
+ if (mCtrl && !bVisible && !bHighlighted)
+ {
+ mWasHiddenBySearch = true;
+ mMenu->setVisible(FALSE);
+ }
+ return bVisible || bHighlighted;
+}
diff --git a/indra/newview/llsearchableui.h b/indra/newview/llsearchableui.h
new file mode 100644
index 0000000000..9741557e49
--- /dev/null
+++ b/indra/newview/llsearchableui.h
@@ -0,0 +1,121 @@
+/**
+* @file llsearchableui.h
+*
+* $LicenseInfo:firstyear=2019&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2019, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#ifndef LL_SEARCHABLE_UI_H
+#define LL_SEARCHABLE_UI_H
+
+class LLMenuItemGL;
+class LLView;
+class LLPanel;
+class LLTabContainer;
+
+#include "llsearchablecontrol.h"
+
+namespace ll
+{
+ namespace prefs
+ {
+ struct SearchableItem;
+ struct PanelData;
+ struct TabContainerData;
+
+ typedef boost::shared_ptr< SearchableItem > SearchableItemPtr;
+ typedef boost::shared_ptr< PanelData > PanelDataPtr;
+ typedef boost::shared_ptr< TabContainerData > TabContainerDataPtr;
+
+ typedef std::vector< TabContainerData > tTabContainerDataList;
+ typedef std::vector< SearchableItemPtr > tSearchableItemList;
+ typedef std::vector< PanelDataPtr > tPanelDataList;
+
+ struct SearchableItem
+ {
+ LLWString mLabel;
+ LLView const *mView;
+ ll::ui::SearchableControl const *mCtrl;
+
+ std::vector< boost::shared_ptr< SearchableItem > > mChildren;
+
+ virtual ~SearchableItem();
+
+ void setNotHighlighted();
+ virtual bool hightlightAndHide( LLWString const &aFilter );
+ };
+
+ struct PanelData
+ {
+ LLPanel const *mPanel;
+ std::string mLabel;
+
+ std::vector< boost::shared_ptr< SearchableItem > > mChildren;
+ std::vector< boost::shared_ptr< PanelData > > mChildPanel;
+
+ virtual ~PanelData();
+
+ virtual bool hightlightAndHide( LLWString const &aFilter );
+ };
+
+ struct TabContainerData: public PanelData
+ {
+ LLTabContainer *mTabContainer;
+ virtual bool hightlightAndHide( LLWString const &aFilter );
+ };
+
+ struct SearchData
+ {
+ TabContainerDataPtr mRootTab;
+ LLWString mLastFilter;
+ };
+ }
+ namespace statusbar
+ {
+ struct SearchableItem;
+
+ typedef boost::shared_ptr< SearchableItem > SearchableItemPtr;
+
+ typedef std::vector< SearchableItemPtr > tSearchableItemList;
+
+ struct SearchableItem
+ {
+ LLWString mLabel;
+ LLMenuItemGL *mMenu;
+ tSearchableItemList mChildren;
+ ll::ui::SearchableControl const *mCtrl;
+ bool mWasHiddenBySearch;
+
+ SearchableItem();
+
+ void setNotHighlighted( );
+ bool hightlightAndHide( LLWString const &aFilter, bool hide = true );
+ };
+
+ struct SearchData
+ {
+ SearchableItemPtr mRootMenu;
+ LLWString mLastFilter;
+ };
+ }
+}
+
+#endif
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 4a2d545b33..56be902254 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -3857,6 +3857,14 @@ BOOL LLSelectMgr::selectGetAggregateTexturePermissions(LLAggregatePermissions& r
return TRUE;
}
+BOOL LLSelectMgr::isSelfAvatarSelected()
+{
+ if (mAllowSelectAvatar)
+ {
+ return (getSelection()->getObjectCount() == 1) && (getSelection()->getFirstRootObject() == gAgentAvatarp);
+ }
+ return FALSE;
+}
//--------------------------------------------------------------------
// Duplicate objects
@@ -6796,8 +6804,28 @@ void LLSelectMgr::pauseAssociatedAvatars()
mSelectedObjects->mSelectType = getSelectTypeForObject(object);
+ bool is_attached = false;
if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT &&
- isAgentAvatarValid() && object->getParent() != NULL)
+ isAgentAvatarValid())
+ {
+ // Selection can be obsolete, confirm that this is an attachment
+ LLViewerObject* parent = (LLViewerObject*)object->getParent();
+ while (parent != NULL)
+ {
+ if (parent->isAvatar())
+ {
+ is_attached = true;
+ break;
+ }
+ else
+ {
+ parent = (LLViewerObject*)parent->getParent();
+ }
+ }
+ }
+
+
+ if (is_attached)
{
if (object->isAnimatedObject())
{
@@ -6815,14 +6843,12 @@ void LLSelectMgr::pauseAssociatedAvatars()
mPauseRequests.push_back(gAgentAvatarp->requestPause());
}
}
- else
+ else if (object && object->isAnimatedObject() && object->getControlAvatar())
{
- if (object && object->isAnimatedObject() && object->getControlAvatar())
- {
- // Is a non-attached animated object. Pause the control avatar.
- mPauseRequests.push_back(object->getControlAvatar()->requestPause());
- }
+ // Is a non-attached animated object. Pause the control avatar.
+ mPauseRequests.push_back(object->getControlAvatar()->requestPause());
}
+
}
}
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index caf104178f..9f2ac857a5 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -709,6 +709,8 @@ public:
LLPermissions* findObjectPermissions(const LLViewerObject* object);
+ BOOL isSelfAvatarSelected();
+
void selectDelete(); // Delete on simulator
void selectForceDelete(); // just delete, no into trash
void selectDuplicate(const LLVector3& offset, BOOL select_copy); // Duplicate on simulator
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 37aaece5d6..243ba00457 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -480,8 +480,7 @@ bool idle_startup()
if (!found_template)
{
message_template_path =
- gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE,
- "../Resources/app_settings",
+ gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,
"message_template.msg");
found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */
}
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index 43c0fbd53a..f3c270a97b 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -81,6 +81,8 @@
#include "llparcel.h"
#include "llstring.h"
#include "message.h"
+#include "llsearchableui.h"
+#include "llsearcheditor.h"
// system includes
#include <iomanip>
@@ -113,7 +115,9 @@ LLStatusBar::LLStatusBar(const LLRect& rect)
mBalance(0),
mHealth(100),
mSquareMetersCredit(0),
- mSquareMetersCommitted(0)
+ mSquareMetersCommitted(0),
+ mFilterEdit(NULL), // Edit for filtering
+ mSearchPanel(NULL) // Panel for filtering
{
setRect(rect);
@@ -239,6 +243,16 @@ BOOL LLStatusBar::postBuild()
mPanelNearByMedia->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
mPanelNearByMedia->setVisible(FALSE);
+ // Hook up and init for filtering
+ mFilterEdit = getChild<LLSearchEditor>( "search_menu_edit" );
+ mSearchPanel = getChild<LLPanel>( "menu_search_panel" );
+
+ mSearchPanel->setVisible(gSavedSettings.getBOOL("MenuSearch"));
+ mFilterEdit->setKeystrokeCallback(boost::bind(&LLStatusBar::onUpdateFilterTerm, this));
+ mFilterEdit->setCommitCallback(boost::bind(&LLStatusBar::onUpdateFilterTerm, this));
+ collectSearchableItems();
+ gSavedSettings.getControl("MenuSearch")->getCommitSignal()->connect(boost::bind(&LLStatusBar::updateMenuSearchVisibility, this, _2));
+
return TRUE;
}
@@ -318,6 +332,7 @@ void LLStatusBar::setVisibleForMouselook(bool visible)
mMediaToggle->setVisible(visible);
mSGBandwidth->setVisible(visible);
mSGPacketLoss->setVisible(visible);
+ mSearchPanel->setVisible(visible && gSavedSettings.getBOOL("MenuSearch"));
setBackgroundVisible(visible);
mIconPresets->setVisible(visible);
}
@@ -358,6 +373,12 @@ void LLStatusBar::setBalance(S32 balance)
balance_bg_view->setShape(balance_bg_rect);
}
+ // If the search panel is shown, move this according to the new balance width. Parcel text will reshape itself in setParcelInfoText
+ if (mSearchPanel && mSearchPanel->getVisible())
+ {
+ updateMenuSearchPosition();
+ }
+
if (mBalance && (fabs((F32)(mBalance - balance)) > gSavedSettings.getF32("UISndMoneyChangeThreshold")))
{
if (mBalance > balance)
@@ -570,6 +591,75 @@ void LLStatusBar::onVolumeChanged(const LLSD& newvalue)
refresh();
}
+void LLStatusBar::onUpdateFilterTerm()
+{
+ LLWString searchValue = utf8str_to_wstring( mFilterEdit->getValue() );
+ LLWStringUtil::toLower( searchValue );
+
+ if( !mSearchData || mSearchData->mLastFilter == searchValue )
+ return;
+
+ mSearchData->mLastFilter = searchValue;
+
+ mSearchData->mRootMenu->hightlightAndHide( searchValue );
+ gMenuBarView->needsArrange();
+}
+
+void collectChildren( LLMenuGL *aMenu, ll::statusbar::SearchableItemPtr aParentMenu )
+{
+ for( U32 i = 0; i < aMenu->getItemCount(); ++i )
+ {
+ LLMenuItemGL *pMenu = aMenu->getItem( i );
+
+ ll::statusbar::SearchableItemPtr pItem( new ll::statusbar::SearchableItem );
+ pItem->mCtrl = pMenu;
+ pItem->mMenu = pMenu;
+ pItem->mLabel = utf8str_to_wstring( pMenu->ll::ui::SearchableControl::getSearchText() );
+ LLWStringUtil::toLower( pItem->mLabel );
+ aParentMenu->mChildren.push_back( pItem );
+
+ LLMenuItemBranchGL *pBranch = dynamic_cast< LLMenuItemBranchGL* >( pMenu );
+ if( pBranch )
+ collectChildren( pBranch->getBranch(), pItem );
+ }
+
+}
+
+void LLStatusBar::collectSearchableItems()
+{
+ mSearchData.reset( new ll::statusbar::SearchData );
+ ll::statusbar::SearchableItemPtr pItem( new ll::statusbar::SearchableItem );
+ mSearchData->mRootMenu = pItem;
+ collectChildren( gMenuBarView, pItem );
+}
+
+void LLStatusBar::updateMenuSearchVisibility(const LLSD& data)
+{
+ bool visible = data.asBoolean();
+ mSearchPanel->setVisible(visible);
+ if (!visible)
+ {
+ mFilterEdit->setText(LLStringUtil::null);
+ onUpdateFilterTerm();
+ }
+ else
+ {
+ updateMenuSearchPosition();
+ }
+}
+
+void LLStatusBar::updateMenuSearchPosition()
+{
+ const S32 HPAD = 12;
+ LLRect balanceRect = getChildView("balance_bg")->getRect();
+ LLRect searchRect = mSearchPanel->getRect();
+ S32 w = searchRect.getWidth();
+ searchRect.mLeft = balanceRect.mLeft - w - HPAD;
+ searchRect.mRight = searchRect.mLeft + w;
+ mSearchPanel->setShape( searchRect );
+}
+
+
// Implements secondlife:///app/balance/request to request a L$ balance
// update via UDP message system. JC
class LLBalanceHandler : public LLCommandHandler
diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h
index a3326e752a..403d590aca 100644
--- a/indra/newview/llstatusbar.h
+++ b/indra/newview/llstatusbar.h
@@ -45,7 +45,15 @@ class LLPanelPresetsPulldown;
class LLPanelVolumePulldown;
class LLPanelNearByMedia;
class LLIconCtrl;
+class LLSearchEditor;
+namespace ll
+{
+ namespace statusbar
+ {
+ struct SearchData;
+ }
+}
class LLStatusBar
: public LLPanel
{
@@ -99,6 +107,15 @@ private:
static void onClickMediaToggle(void* data);
static void onClickBalance(void* data);
+ LLSearchEditor *mFilterEdit;
+ LLPanel *mSearchPanel;
+ void onUpdateFilterTerm();
+
+ std::unique_ptr< ll::statusbar::SearchData > mSearchData;
+ void collectSearchableItems();
+ void updateMenuSearchVisibility( const LLSD& data );
+ void updateMenuSearchPosition();
+
private:
LLTextBox *mTextTime;
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 633e025478..e5af47ab6c 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -825,10 +825,10 @@ void LLTextureCacheWorker::endWork(S32 param, bool aborted)
LLTextureCache::LLTextureCache(bool threaded)
: LLWorkerThread("TextureCache", threaded),
- mWorkersMutex(NULL),
- mHeaderMutex(NULL),
- mListMutex(NULL),
- mFastCacheMutex(NULL),
+ mWorkersMutex(),
+ mHeaderMutex(),
+ mListMutex(),
+ mFastCacheMutex(),
mHeaderAPRFile(NULL),
mReadOnly(TRUE), //do not allow to change the texture cache until setReadOnly() is called.
mTexturesSizeTotal(0),
@@ -1038,11 +1038,11 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL texture_cache
{
llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized.
- S64 header_size = (max_size / 100) * 36; //0.36 * max_size
- S64 max_entries = header_size / (TEXTURE_CACHE_ENTRY_SIZE + TEXTURE_FAST_CACHE_ENTRY_SIZE);
+ S64 entries_size = (max_size * 36) / 100; //0.36 * max_size
+ S64 max_entries = entries_size / (TEXTURE_CACHE_ENTRY_SIZE + TEXTURE_FAST_CACHE_ENTRY_SIZE);
sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries));
- header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE;
- max_size -= header_size;
+ entries_size = sCacheMaxEntries * (TEXTURE_CACHE_ENTRY_SIZE + TEXTURE_FAST_CACHE_ENTRY_SIZE);
+ max_size -= entries_size;
if (sCacheMaxTexturesSize > 0)
sCacheMaxTexturesSize = llmin(sCacheMaxTexturesSize, max_size);
else
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index 987b9375c0..81ea7aeee2 100644
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -221,7 +221,7 @@ private:
typedef std::map<LLUUID,S32> size_map_t;
size_map_t mTexturesSizeMap;
S64 mTexturesSizeTotal;
- LLAtomic32<BOOL> mDoPurge;
+ LLAtomicBool mDoPurge;
typedef std::map<S32, Entry> idx_entry_map_t;
idx_entry_map_t mUpdatedEntryMap;
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index a5a2eec246..1396a8546d 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -131,7 +131,7 @@ LLFloaterTexturePicker::~LLFloaterTexturePicker()
void LLFloaterTexturePicker::setImageID(const LLUUID& image_id, bool set_selection /*=true*/)
{
- if( mImageAssetID != image_id && mActive)
+ if( ((mImageAssetID != image_id) || mTentative) && mActive)
{
mNoCopyTextureSelected = FALSE;
mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
@@ -1096,6 +1096,10 @@ void LLTextureCtrl::setVisible( BOOL visible )
void LLTextureCtrl::setEnabled( BOOL enabled )
{
LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
+ if( floaterp )
+ {
+ floaterp->setActive(enabled);
+ }
if( enabled )
{
std::string tooltip;
@@ -1110,11 +1114,6 @@ void LLTextureCtrl::setEnabled( BOOL enabled )
closeDependentFloater();
}
- if( floaterp )
- {
- floaterp->setActive(enabled);
- }
-
mCaption->setEnabled( enabled );
LLView::setEnabled( enabled );
@@ -1215,9 +1214,10 @@ void LLTextureCtrl::showPicker(BOOL take_focus)
void LLTextureCtrl::closeDependentFloater()
{
LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
- if( floaterp )
+ if( floaterp && floaterp->isInVisibleChain())
{
floaterp->setOwner(NULL);
+ floaterp->setVisible(FALSE);
floaterp->closeFloater();
}
}
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 1f69939c46..ca401f5c17 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -925,7 +925,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
mCanUseHTTP(true),
mRetryAttempt(0),
mActiveCount(0),
- mWorkMutex(NULL),
+ mWorkMutex(),
mFirstPacket(0),
mLastPacket(-1),
mTotalPackets(0),
@@ -2543,8 +2543,8 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
mDebugPause(FALSE),
mPacketCount(0),
mBadPacketCount(0),
- mQueueMutex(getAPRPool()),
- mNetworkQueueMutex(getAPRPool()),
+ mQueueMutex(),
+ mNetworkQueueMutex(),
mTextureCache(cache),
mImageDecodeThread(imagedecodethread),
mTextureBandwidth(0),
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index cfa312ccd9..19369137b7 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -35,7 +35,6 @@
#include "lluuid.h"
#include "llworkerthread.h"
#include "lltextureinfo.h"
-#include "llapr.h"
#include "llimageworker.h"
#include "httprequest.h"
#include "httpoptions.h"
diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp
index f7dc32d0d7..817d1dd7b4 100644
--- a/indra/newview/lltoastgroupnotifypanel.cpp
+++ b/indra/newview/lltoastgroupnotifypanel.cpp
@@ -84,14 +84,14 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(const LLNotificationPtr& notifi
//message body
const std::string& message = payload["message"].asString();
- std::string timeStr = "["+LLTrans::getString("UTCTimeWeek")+"],["
- +LLTrans::getString("UTCTimeDay")+"] ["
- +LLTrans::getString("UTCTimeMth")+"] ["
- +LLTrans::getString("UTCTimeYr")+"] ["
- +LLTrans::getString("UTCTimeHr")+"]:["
- +LLTrans::getString("UTCTimeMin")+"]:["
- +LLTrans::getString("UTCTimeSec")+"] ["
- +LLTrans::getString("UTCTimeTimezone")+"]";
+ std::string timeStr = "[" + LLTrans::getString("TimeWeek") + "], ["
+ + LLTrans::getString("TimeMonth") + "]/["
+ + LLTrans::getString("TimeDay") + "]/["
+ + LLTrans::getString("TimeYear") + "] ["
+ + LLTrans::getString("TimeHour") + "]:["
+ + LLTrans::getString("TimeMin") + "] ["
+ + LLTrans::getString("TimeTimezone") + "]";
+
const LLDate timeStamp = notification->getDate();
LLDate notice_date = timeStamp.notNull() ? timeStamp : payload["received_time"].asDate();
LLSD substitution;
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp
index e3a856be5c..a2116817a2 100644
--- a/indra/newview/lltoastnotifypanel.cpp
+++ b/indra/newview/lltoastnotifypanel.cpp
@@ -46,8 +46,6 @@
const S32 BOTTOM_PAD = VPAD * 3;
const S32 IGNORE_BTN_TOP_DELTA = 3*VPAD;//additional ignore_btn padding
S32 BUTTON_WIDTH = 90;
-// *TODO: magic numbers - copied from llnotify.cpp(250)
-const S32 MAX_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE;
//static
@@ -319,7 +317,7 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images )
mTextBox = getChild<LLTextEditor>("text_editor_box");
}
- mTextBox->setMaxTextLength(MAX_LENGTH);
+ mTextBox->setMaxTextLength(LLToastPanel::MAX_TEXT_LENGTH);
mTextBox->setVisible(TRUE);
mTextBox->setPlainText(!show_images);
mTextBox->setContentTrusted(is_content_trusted);
@@ -411,7 +409,7 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images )
//.xml file intially makes info panel only follow left/right/top. This is so that when control buttons are added the info panel
//can shift upward making room for the buttons inside mControlPanel. After the buttons are added, the info panel can then be set to follow 'all'.
mInfoPanel->setFollowsAll();
- snapToMessageHeight(mTextBox, MAX_LENGTH);
+ snapToMessageHeight(mTextBox, LLToastPanel::MAX_TEXT_LENGTH);
// reshape the panel to its previous size
if (current_rect.notEmpty())
@@ -472,7 +470,7 @@ void LLIMToastNotifyPanel::snapToMessageHeight()
//Add message height if it is visible
if (mTextBox->getVisible())
{
- S32 new_panel_height = computeSnappedToMessageHeight(mTextBox, MAX_LENGTH);
+ S32 new_panel_height = computeSnappedToMessageHeight(mTextBox, LLToastPanel::MAX_TEXT_LENGTH);
//reshape the panel with new height
if (new_panel_height != getRect().getHeight())
diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp
index e1b764a943..7c624d5b50 100644
--- a/indra/newview/lltoastpanel.cpp
+++ b/indra/newview/lltoastpanel.cpp
@@ -26,6 +26,7 @@
#include "llviewerprecompiledheaders.h"
+#include "lldbstrings.h"
#include "llpanelgenerictip.h"
#include "llpanelonlinestatus.h"
#include "llnotifications.h"
@@ -35,6 +36,8 @@
//static
const S32 LLToastPanel::MIN_PANEL_HEIGHT = 40; // VPAD(4)*2 + ICON_HEIGHT(32)
+// 'magic numbers', consider initializing (512+20) part from xml/notifications
+const S32 LLToastPanel::MAX_TEXT_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE;
LLToastPanel::LLToastPanel(const LLNotificationPtr& notification)
{
diff --git a/indra/newview/lltoastpanel.h b/indra/newview/lltoastpanel.h
index 51630381f2..6a9b72a5ae 100644
--- a/indra/newview/lltoastpanel.h
+++ b/indra/newview/lltoastpanel.h
@@ -49,6 +49,7 @@ public:
virtual const LLUUID& getID();
static const S32 MIN_PANEL_HEIGHT;
+ static const S32 MAX_TEXT_LENGTH;
/**
* Builder method for constructing notification specific panels.
diff --git a/indra/newview/lltoastscripttextbox.cpp b/indra/newview/lltoastscripttextbox.cpp
index 518c6c0ee4..eb86a44055 100644
--- a/indra/newview/lltoastscripttextbox.cpp
+++ b/indra/newview/lltoastscripttextbox.cpp
@@ -36,8 +36,6 @@
#include "llviewertexteditor.h"
const S32 LLToastScriptTextbox::DEFAULT_MESSAGE_MAX_LINE_COUNT= 14;
-// *TODO: magic numbers - copied from lltoastnotifypanel.cpp(50) which was copied from llnotify.cpp(250)
-const S32 MAX_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE;
LLToastScriptTextbox::LLToastScriptTextbox(const LLNotificationPtr& notification)
: LLToastPanel(notification)
@@ -45,7 +43,7 @@ LLToastScriptTextbox::LLToastScriptTextbox(const LLNotificationPtr& notification
buildFromFile( "panel_notify_textbox.xml");
mInfoText = getChild<LLTextEditor>("text_editor_box");
- mInfoText->setMaxTextLength(MAX_LENGTH);
+ mInfoText->setMaxTextLength(LLToastPanel::MAX_TEXT_LENGTH);
mInfoText->setValue(notification->getMessage());
getChild<LLButton>("ignore_btn")->setClickedCallback(boost::bind(&LLToastScriptTextbox::onClickIgnore, this));
diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp
index 4aad650b68..b5d78f3654 100644
--- a/indra/newview/lltool.cpp
+++ b/indra/newview/lltool.cpp
@@ -191,7 +191,9 @@ LLTool* LLTool::getOverrideTool(MASK mask)
{
return NULL;
}
- if (gSavedSettings.getBOOL("EnableAltZoom"))
+
+ static LLCachedControl<bool> alt_zoom(gSavedSettings, "EnableAltZoom", true);
+ if (alt_zoom)
{
if (mask & MASK_ALT)
{
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 9e37ca0394..697db01d11 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -111,11 +111,24 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
mMouseOutsideSlop = FALSE;
mMouseDownX = x;
mMouseDownY = y;
- LLTimer pick_timer;
- BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
- //left mouse down always picks transparent (but see handleMouseUp)
- mPick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged);
- LL_INFOS() << "pick_rigged is " << (S32) pick_rigged << " pick time elapsed " << pick_timer.getElapsedTimeF32() << LL_ENDL;
+ LLTimer pick_timer;
+ BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
+ mPick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged);
+ LLViewerObject *object = mPick.getObject();
+ LLViewerObject *parent = object ? object->getRootEdit() : NULL;
+ if (!object
+ || object->isAttachment()
+ || object->getClickAction() == CLICK_ACTION_DISABLED
+ || (!useClickAction(mask, object, parent) && !object->flagHandleTouch() && !(parent && parent->flagHandleTouch())))
+ {
+ // Unless we are hovering over actionable visible object
+ // left mouse down always picks transparent (but see handleMouseUp).
+ // Also see LLToolPie::handleHover() - priorities are a bit different there.
+ // Todo: we need a more consistent set of rules to work with
+ mPick = gViewerWindow->pickImmediate(x, y, TRUE /*transparent*/, pick_rigged);
+ }
+ LL_INFOS() << "pick_rigged is " << (S32) pick_rigged << " pick time elapsed " << pick_timer.getElapsedTimeF32() << LL_ENDL;
+
mPick.mKeyMask = mask;
mMouseButtonDown = true;
@@ -857,13 +870,11 @@ static bool needs_tooltip(LLSelectNode* nodep)
BOOL LLToolPie::handleTooltipLand(std::string line, std::string tooltip_msg)
{
- LLViewerParcelMgr::getInstance()->setHoverParcel( mHoverPick.mPosGlobal );
- //
- // Do not show hover for land unless prefs are set to allow it.
- //
-
+ // Do not show hover for land unless prefs are set to allow it.
if (!gSavedSettings.getBOOL("ShowLandHoverTip")) return TRUE;
-
+
+ LLViewerParcelMgr::getInstance()->setHoverParcel( mHoverPick.mPosGlobal );
+
// Didn't hit an object, but since we have a land point we
// must be hovering over land.
diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp
index 375dce485d..4e07223784 100644
--- a/indra/newview/llversioninfo.cpp
+++ b/indra/newview/llversioninfo.cpp
@@ -101,14 +101,11 @@ namespace
{
// LL_VIEWER_CHANNEL is a macro defined on the compiler command line. The
// macro expands to the string name of the channel, but without quotes. We
- // need to turn it into a quoted string. This macro trick does that.
-#define stringize_inner(x) #x
-#define stringize_outer(x) stringize_inner(x)
-
+ // need to turn it into a quoted string. LL_TO_STRING() does that.
/// Storage of the channel name the viewer is using.
// The channel name is set by hardcoded constant,
// or by calling LLVersionInfo::resetChannel()
- std::string sWorkingChannelName(stringize_outer(LL_VIEWER_CHANNEL));
+ std::string sWorkingChannelName(LL_TO_STRING(LL_VIEWER_CHANNEL));
// Storage for the "version and channel" string.
// This will get reset too.
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 88984d518a..a699491e1b 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -219,20 +219,20 @@ static bool handleAnisotropicChanged(const LLSD& newvalue)
static bool handleVolumeLODChanged(const LLSD& newvalue)
{
- LLVOVolume::sLODFactor = (F32) newvalue.asReal();
+ LLVOVolume::sLODFactor = llclamp((F32) newvalue.asReal(), 0.01f, MAX_LOD_FACTOR);
LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f;
return true;
}
static bool handleAvatarLODChanged(const LLSD& newvalue)
{
- LLVOAvatar::sLODFactor = (F32) newvalue.asReal();
+ LLVOAvatar::sLODFactor = llclamp((F32) newvalue.asReal(), 0.f, MAX_AVATAR_LOD_FACTOR);
return true;
}
static bool handleAvatarPhysicsLODChanged(const LLSD& newvalue)
{
- LLVOAvatar::sPhysicsLODFactor = (F32) newvalue.asReal();
+ LLVOAvatar::sPhysicsLODFactor = llclamp((F32) newvalue.asReal(), 0.f, MAX_AVATAR_LOD_FACTOR);
return true;
}
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 0ebacddd9b..a7b2fafddf 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -90,6 +90,7 @@
#include "llfloatermediasettings.h"
#include "llfloatermemleak.h"
#include "llfloatermodelpreview.h"
+#include "llfloatermyscripts.h"
#include "llfloaternamedesc.h"
#include "llfloaternotificationsconsole.h"
#include "llfloaternotificationstabbed.h"
@@ -335,6 +336,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>);
LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLScriptFloater>);
LLFloaterReg::add("script_limits", "floater_script_limits.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptLimits>);
+ LLFloaterReg::add("my_scripts", "floater_my_scripts.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyScripts>);
LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater);
LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>);
LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>);
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 22a21c9ca3..d8745b1eca 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -682,8 +682,8 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
std::vector<LLViewerMediaImpl*> proximity_order;
- bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia");
- bool inworld_audio_enabled = gSavedSettings.getBOOL("AudioStreamingMusic");
+ static LLCachedControl<bool> inworld_media_enabled(gSavedSettings, "AudioStreamingMedia", true);
+ static LLCachedControl<bool> inworld_audio_enabled(gSavedSettings, "AudioStreamingMusic", true);
U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal");
U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal");
U32 max_low = gSavedSettings.getU32("PluginInstancesLow");
@@ -941,7 +941,8 @@ void LLViewerMedia::setAllMediaEnabled(bool val)
LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel());
}
- if (gSavedSettings.getBOOL("AudioStreamingMusic") &&
+ static LLCachedControl<bool> audio_streaming_music(gSavedSettings, "AudioStreamingMusic", true);
+ if (audio_streaming_music &&
!LLViewerMedia::isParcelAudioPlaying() &&
gAudiop &&
LLViewerMedia::hasParcelAudio())
@@ -1012,7 +1013,8 @@ void LLViewerMedia::setAllMediaPaused(bool val)
LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel());
}
- if (gSavedSettings.getBOOL("AudioStreamingMusic") &&
+ static LLCachedControl<bool> audio_streaming_music(gSavedSettings, "AudioStreamingMusic", true);
+ if (audio_streaming_music &&
!LLViewerMedia::isParcelAudioPlaying() &&
gAudiop &&
LLViewerMedia::hasParcelAudio())
@@ -3318,8 +3320,39 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
}
else
{
- // Don't track redirects.
- setNavState(MEDIANAVSTATE_NONE);
+ bool internal_nav = false;
+ if (url != mCurrentMediaURL)
+ {
+ // Check if it is internal navigation
+ // Note: Not sure if we should detect internal navigations as 'address change',
+ // but they are not redirects and do not cause NAVIGATE_BEGIN (also see SL-1005)
+ size_t pos = url.find("#");
+ if (pos != std::string::npos)
+ {
+ // assume that new link always have '#', so this is either
+ // transfer from 'link#1' to 'link#2' or from link to 'link#2'
+ // filter out cases like 'redirect?link'
+ std::string base_url = url.substr(0, pos);
+ pos = mCurrentMediaURL.find(base_url);
+ if (pos == 0)
+ {
+ // base link hasn't changed
+ internal_nav = true;
+ }
+ }
+ }
+
+ if (internal_nav)
+ {
+ // Internal navigation by '#'
+ mCurrentMediaURL = url;
+ setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED);
+ }
+ else
+ {
+ // Don't track redirects.
+ setNavState(MEDIANAVSTATE_NONE);
+ }
}
}
break;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 6c52f118ad..ba68ce4cf4 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7068,25 +7068,19 @@ BOOL object_selected_and_point_valid()
BOOL object_is_wearable()
{
- if (!object_selected_and_point_valid())
+ if (!isAgentAvatarValid())
{
return FALSE;
}
- if (sitting_on_selection())
+ if (!object_selected_and_point_valid())
{
return FALSE;
}
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin();
- iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++)
+ if (sitting_on_selection())
{
- LLSelectNode* node = *iter;
- if (node->mPermissions->getOwner() == gAgent.getID())
- {
- return TRUE;
- }
+ return FALSE;
}
- return FALSE;
+ return gAgentAvatarp->canAttachMoreObjects();
}
@@ -9207,7 +9201,7 @@ void initialize_menus()
enable.add("Object.EnableOpen", boost::bind(&enable_object_open));
enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1));
enable.add("Object.EnableDelete", boost::bind(&enable_object_delete));
- enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid));
+ enable.add("Object.EnableWear", boost::bind(&object_is_wearable));
enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up));
enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1));
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index d2a5578568..a9a91b158b 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -175,7 +175,7 @@ void LLFilePickerThread::run()
//static
void LLFilePickerThread::initClass()
{
- sMutex = new LLMutex(NULL);
+ sMutex = new LLMutex();
}
//static
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 981d226824..e50c8ee9f0 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -5531,17 +5531,6 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp
void script_question_mute(const LLUUID& item_id, const std::string& object_name);
-bool unknown_script_question_cb(const LLSD& notification, const LLSD& response)
-{
- // Only care if they muted the object here.
- if ( response["Mute"] ) // mute
- {
- LLUUID task_id = notification["payload"]["task_id"].asUUID();
- script_question_mute(task_id,notification["payload"]["object_name"].asString());
- }
- return false;
-}
-
void experiencePermissionBlock(LLUUID experience, LLSD result)
{
LLSD permission;
@@ -5647,8 +5636,7 @@ void script_question_mute(const LLUUID& task_id, const std::string& object_name)
bool matches(const LLNotificationPtr notification) const
{
if (notification->getName() == "ScriptQuestionCaution"
- || notification->getName() == "ScriptQuestion"
- || notification->getName() == "UnknownScriptQuestion")
+ || notification->getName() == "ScriptQuestion")
{
return (notification->getPayload()["task_id"].asUUID() == blocked_id);
}
@@ -5665,7 +5653,6 @@ void script_question_mute(const LLUUID& task_id, const std::string& object_name)
static LLNotificationFunctorRegistration script_question_cb_reg_1("ScriptQuestion", script_question_cb);
static LLNotificationFunctorRegistration script_question_cb_reg_2("ScriptQuestionCaution", script_question_cb);
static LLNotificationFunctorRegistration script_question_cb_reg_3("ScriptQuestionExperience", script_question_cb);
-static LLNotificationFunctorRegistration unknown_script_question_cb_reg("UnknownScriptQuestion", unknown_script_question_cb);
void process_script_experience_details(const LLSD& experience_details, LLSD args, LLSD payload)
{
@@ -5778,14 +5765,12 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
args["QUESTIONS"] = script_question;
if (known_questions != questions)
- { // This is in addition to the normal dialog.
- LLSD payload;
- payload["task_id"] = taskid;
- payload["item_id"] = itemid;
- payload["object_name"] = object_name;
-
- args["DOWNLOADURL"] = LLTrans::getString("ViewerDownloadURL");
- LLNotificationsUtil::add("UnknownScriptQuestion",args,payload);
+ {
+ // This is in addition to the normal dialog.
+ // Viewer got a request for not supported/implemented permission
+ LL_WARNS("Messaging") << "Object \"" << object_name << "\" requested " << script_question
+ << " permission. Permission is unknown and can't be granted. Item id: " << itemid
+ << " taskid:" << taskid << LL_ENDL;
}
if (known_questions)
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 1e46a1cf9e..ec1095813b 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -127,6 +127,7 @@ BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE
// sMaxUpdateInterpolationTime must be greater than sPhaseOutUpdateInterpolationTime
F64Seconds LLViewerObject::sMaxUpdateInterpolationTime(3.0); // For motion interpolation: after X seconds with no updates, don't predict object motion
F64Seconds LLViewerObject::sPhaseOutUpdateInterpolationTime(2.0); // For motion interpolation: after Y seconds with no updates, taper off motion prediction
+F64Seconds LLViewerObject::sMaxRegionCrossingInterpolationTime(1.0);// For motion interpolation: don't interpolate over this time on region crossing
std::map<std::string, U32> LLViewerObject::sObjectDataMap;
@@ -260,6 +261,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mLastInterpUpdateSecs(0.f),
mLastMessageUpdateSecs(0.f),
mLatestRecvPacketID(0),
+ mRegionCrossExpire(0),
mData(NULL),
mAudioSourcep(NULL),
mAudioGain(1.f),
@@ -2487,7 +2489,7 @@ void LLViewerObject::loadFlags(U32 flags)
return;
}
-void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &time)
+void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &frame_time)
{
//static LLTrace::BlockTimerStatHandle ftm("Viewer Object");
//LL_RECORD_BLOCK_TIME(ftm);
@@ -2498,19 +2500,19 @@ void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &time)
{
// calculate dt from last update
F32 time_dilation = mRegionp ? mRegionp->getTimeDilation() : 1.0f;
- F32 dt_raw = ((F64Seconds)time - mLastInterpUpdateSecs).value();
+ F32 dt_raw = ((F64Seconds)frame_time - mLastInterpUpdateSecs).value();
F32 dt = time_dilation * dt_raw;
applyAngularVelocity(dt);
if (isAttachment())
{
- mLastInterpUpdateSecs = (F64Seconds)time;
+ mLastInterpUpdateSecs = (F64Seconds)frame_time;
return;
}
else
{ // Move object based on it's velocity and rotation
- interpolateLinearMotion(time, dt);
+ interpolateLinearMotion(frame_time, dt);
}
}
@@ -2520,7 +2522,7 @@ void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &time)
// Move an object due to idle-time viewer side updates by interpolating motion
-void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, const F32SecondsImplicit& dt_seconds)
+void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& frame_time, const F32SecondsImplicit& dt_seconds)
{
// linear motion
// PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object
@@ -2532,7 +2534,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con
// zeroing it out
F32 dt = dt_seconds;
- F64Seconds time_since_last_update = time - mLastMessageUpdateSecs;
+ F64Seconds time_since_last_update = frame_time - mLastMessageUpdateSecs;
if (time_since_last_update <= (F64Seconds)0.0 || dt <= 0.f)
{
return;
@@ -2580,7 +2582,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con
(time_since_last_packet > sPhaseOutUpdateInterpolationTime))
{
// Start to reduce motion interpolation since we haven't seen a server update in a while
- F64Seconds time_since_last_interpolation = time - mLastInterpUpdateSecs;
+ F64Seconds time_since_last_interpolation = frame_time - mLastInterpUpdateSecs;
F64 phase_out = 1.0;
if (time_since_last_update > sMaxUpdateInterpolationTime)
{ // Past the time limit, so stop the object
@@ -2635,7 +2637,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con
new_pos.mV[VZ] = llmax(min_height, new_pos.mV[VZ]);
// Check to see if it's going off the region
- LLVector3 temp(new_pos);
+ LLVector3 temp(new_pos.mV[VX], new_pos.mV[VY], 0.f);
if (temp.clamp(0.f, mRegionp->getWidth()))
{ // Going off this region, so see if we might end up on another region
LLVector3d old_pos_global = mRegionp->getPosGlobalFromRegion(getPositionRegion());
@@ -2644,21 +2646,47 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con
// Clip the positions to known regions
LLVector3d clip_pos_global = LLWorld::getInstance()->clipToVisibleRegions(old_pos_global, new_pos_global);
if (clip_pos_global != new_pos_global)
- { // Was clipped, so this means we hit a edge where there is no region to enter
-
- //LL_INFOS() << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global)
- // << " from " << new_pos << LL_ENDL;
- new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global);
+ {
+ // Was clipped, so this means we hit a edge where there is no region to enter
+ LLVector3 clip_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global);
+ LL_DEBUGS("Interpolate") << "Hit empty region edge, clipped predicted position to "
+ << clip_pos
+ << " from " << new_pos << LL_ENDL;
+ new_pos = clip_pos;
// Stop motion and get server update for bouncing on the edge
new_v.clear();
setAcceleration(LLVector3::zero);
}
else
- { // Let predicted movement cross into another region
- //LL_INFOS() << "Predicting region crossing to " << new_pos << LL_ENDL;
+ {
+ // Check for how long we are crossing.
+ // Note: theoretically we can find time from velocity, acceleration and
+ // distance from border to new position, but it is not going to work
+ // if 'phase_out' activates
+ if (mRegionCrossExpire == 0)
+ {
+ // Workaround: we can't accurately figure out time when we cross border
+ // so just write down time 'after the fact', it is far from optimal in
+ // case of lags, but for lags sMaxUpdateInterpolationTime will kick in first
+ LL_DEBUGS("Interpolate") << "Predicted region crossing, new position " << new_pos << LL_ENDL;
+ mRegionCrossExpire = frame_time + sMaxRegionCrossingInterpolationTime;
+ }
+ else if (frame_time > mRegionCrossExpire)
+ {
+ // Predicting crossing over 1s, stop motion
+ // Stop motion
+ LL_DEBUGS("Interpolate") << "Predicting region crossing for too long, stopping at " << new_pos << LL_ENDL;
+ new_v.clear();
+ setAcceleration(LLVector3::zero);
+ mRegionCrossExpire = 0;
+ }
}
}
+ else
+ {
+ mRegionCrossExpire = 0;
+ }
// Set new position and velocity
setPositionRegion(new_pos);
@@ -2669,7 +2697,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con
}
// Update the last time we did anything
- mLastInterpUpdateSecs = time;
+ mLastInterpUpdateSecs = frame_time;
}
@@ -3072,6 +3100,7 @@ void LLViewerObject::unlinkControlAvatar()
if (mControlAvatar)
{
mControlAvatar->markForDeath();
+ mControlAvatar->mRootVolp = NULL;
mControlAvatar = NULL;
}
}
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index d6c8b76147..8b1535851e 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -615,7 +615,7 @@ private:
U32 checkMediaURL(const std::string &media_url);
// Motion prediction between updates
- void interpolateLinearMotion(const F64SecondsImplicit & time, const F32SecondsImplicit & dt);
+ void interpolateLinearMotion(const F64SecondsImplicit & frame_time, const F32SecondsImplicit & dt);
static void initObjectDataMap();
@@ -772,6 +772,7 @@ protected:
F64Seconds mLastInterpUpdateSecs; // Last update for purposes of interpolation
F64Seconds mLastMessageUpdateSecs; // Last update from a message from the simulator
TPACKETID mLatestRecvPacketID; // Latest time stamp on message from simulator
+ F64SecondsImplicit mRegionCrossExpire; // frame time we detected region crossing in + wait time
// extra data sent from the sim...currently only used for tree species info
U8* mData;
@@ -851,6 +852,7 @@ protected:
static void setPhaseOutUpdateInterpolationTime(F32 value) { sPhaseOutUpdateInterpolationTime = (F64Seconds) value; }
static void setMaxUpdateInterpolationTime(F32 value) { sMaxUpdateInterpolationTime = (F64Seconds) value; }
+ static void setMaxRegionCrossingInterpolationTime(F32 value) { sMaxRegionCrossingInterpolationTime = (F64Seconds) value; }
static void setVelocityInterpolate(BOOL value) { sVelocityInterpolate = value; }
static void setPingInterpolate(BOOL value) { sPingInterpolate = value; }
@@ -860,6 +862,7 @@ private:
static F64Seconds sPhaseOutUpdateInterpolationTime; // For motion interpolation
static F64Seconds sMaxUpdateInterpolationTime; // For motion interpolation
+ static F64Seconds sMaxRegionCrossingInterpolationTime; // For motion interpolation
static BOOL sVelocityInterpolate;
static BOOL sPingInterpolate;
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 2aff71367e..932759c86d 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -854,6 +854,7 @@ void LLViewerObjectList::update(LLAgent &agent)
F32 interp_time = gSavedSettings.getF32("InterpolationTime");
F32 phase_out_time = gSavedSettings.getF32("InterpolationPhaseOut");
+ F32 region_interp_time = llclamp(gSavedSettings.getF32("RegionCrossingInterpolationTime"), 0.5f, 5.f);
if (interp_time < 0.0 ||
phase_out_time < 0.0 ||
phase_out_time > interp_time)
@@ -864,6 +865,7 @@ void LLViewerObjectList::update(LLAgent &agent)
}
LLViewerObject::setPhaseOutUpdateInterpolationTime( interp_time );
LLViewerObject::setMaxUpdateInterpolationTime( phase_out_time );
+ LLViewerObject::setMaxRegionCrossingInterpolationTime(region_interp_time);
gAnimateTextures = gSavedSettings.getBOOL("AnimateTextures");
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index f4d14a39fe..416d5d8e2e 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -957,7 +957,7 @@ void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id)
return;
}
- LL_INFOS() << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL;
+ LL_INFOS("ParcelMgr") << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL;
// BUG: Only works for the region containing mWestSouthBottom
LLVector3d east_north_region_check( mEastNorth );
@@ -980,7 +980,7 @@ void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id)
return;
}
- LL_INFOS() << "Region " << region->getOriginGlobal() << LL_ENDL;
+ LL_INFOS("ParcelMgr") << "Region " << region->getOriginGlobal() << LL_ENDL;
LLSD payload;
payload["owner_id"] = owner_id;
@@ -1120,8 +1120,8 @@ LLViewerParcelMgr::ParcelBuyInfo* LLViewerParcelMgr::setupParcelBuy(
if (is_claim)
{
- LL_INFOS() << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL;
- LL_INFOS() << "Region " << region->getOriginGlobal() << LL_ENDL;
+ LL_INFOS("ParcelMgr") << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL;
+ LL_INFOS("ParcelMgr") << "Region " << region->getOriginGlobal() << LL_ENDL;
// BUG: Only works for the region containing mWestSouthBottom
LLVector3d east_north_region_check( mEastNorth );
@@ -1294,8 +1294,6 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag
if (!region)
return;
- //LL_INFOS() << "found region: " << region->getName() << LL_ENDL;
-
LLSD body;
std::string url = region->getCapability("ParcelPropertiesUpdate");
if (!url.empty())
@@ -1304,7 +1302,7 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag
U32 message_flags = 0x01;
body["flags"] = ll_sd_from_U32(message_flags);
parcel->packMessage(body);
- LL_INFOS() << "Sending parcel properties update via capability to: "
+ LL_INFOS("ParcelMgr") << "Sending parcel properties update via capability to: "
<< url << LL_ENDL;
LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
@@ -1333,22 +1331,18 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag
void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos)
{
static U32 last_west, last_south;
-
+ static LLUUID last_region;
// only request parcel info if position has changed outside of the
// last parcel grid step
- U32 west_parcel_step = (U32) floor( pos.mdV[VX] / PARCEL_GRID_STEP_METERS );
- U32 south_parcel_step = (U32) floor( pos.mdV[VY] / PARCEL_GRID_STEP_METERS );
-
+ const U32 west_parcel_step = (U32) floor( pos.mdV[VX] / PARCEL_GRID_STEP_METERS );
+ const U32 south_parcel_step = (U32) floor( pos.mdV[VY] / PARCEL_GRID_STEP_METERS );
+
if ((west_parcel_step == last_west) && (south_parcel_step == last_south))
{
+ // We are staying in same segment
return;
}
- else
- {
- last_west = west_parcel_step;
- last_south = south_parcel_step;
- }
LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos );
if (!region)
@@ -1356,34 +1350,95 @@ void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos)
return;
}
+ LLUUID region_id = region->getRegionID();
+ LLVector3 pos_in_region = region->getPosRegionFromGlobal(pos);
- // Send a rectangle around the point.
- // This means the parcel sent back is at least a rectangle around the point,
- // which is more efficient for public land. Fewer requests are sent. JC
- LLVector3 wsb_region = region->getPosRegionFromGlobal( pos );
+ bool request_properties = false;
+ if (region_id != last_region)
+ {
+ request_properties = true;
+ }
+ else
+ {
+ // Check if new position is in same parcel.
+ // This check is not ideal, since it checks by way of straight lines.
+ // So sometimes (small parcel in the middle of large one) it can
+ // decide that parcel actually changed, but it still allows to
+ // reduce amount of requests significantly
- F32 west = PARCEL_GRID_STEP_METERS * floor( wsb_region.mV[VX] / PARCEL_GRID_STEP_METERS );
- F32 south = PARCEL_GRID_STEP_METERS * floor( wsb_region.mV[VY] / PARCEL_GRID_STEP_METERS );
+ S32 west_parcel_local = (S32)(pos_in_region.mV[VX] / PARCEL_GRID_STEP_METERS);
+ S32 south_parcel_local = (S32)(pos_in_region.mV[VY] / PARCEL_GRID_STEP_METERS);
- F32 east = west + PARCEL_GRID_STEP_METERS;
- F32 north = south + PARCEL_GRID_STEP_METERS;
+ LLViewerParcelOverlay* overlay = region->getParcelOverlay();
+ if (!overlay)
+ {
+ request_properties = true;
+ }
+ while (!request_properties && west_parcel_step < last_west)
+ {
+ S32 segment_shift = last_west - west_parcel_step;
+ request_properties = overlay->parcelLineFlags(south_parcel_local, west_parcel_local + segment_shift) & PARCEL_WEST_LINE;
+ last_west--;
+ }
+ while (!request_properties && south_parcel_step < last_south)
+ {
+ S32 segment_shift = last_south - south_parcel_step;
+ request_properties = overlay->parcelLineFlags(south_parcel_local + segment_shift, west_parcel_local) & PARCEL_SOUTH_LINE;
+ last_south--;
+ }
+ // Note: could have just swapped values, reused first two 'while' and set last_south, last_west separately,
+ // but this looks to be easier to understand/straightforward/less bulky
+ while (!request_properties && west_parcel_step > last_west)
+ {
+ S32 segment_shift = west_parcel_step - last_west;
+ request_properties = overlay->parcelLineFlags(south_parcel_local, west_parcel_local - segment_shift + 1) & PARCEL_WEST_LINE;
+ last_west++;
+ }
+ while (!request_properties && south_parcel_step > last_south)
+ {
+ S32 segment_shift = south_parcel_step - last_south;
+ request_properties = overlay->parcelLineFlags(south_parcel_local - segment_shift + 1, west_parcel_local) & PARCEL_SOUTH_LINE;
+ last_south++;
+ }
- // Send request message
- LLMessageSystem *msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_ParcelPropertiesRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
- msg->nextBlockFast(_PREHASH_ParcelData);
- msg->addS32Fast(_PREHASH_SequenceID, HOVERED_PARCEL_SEQ_ID );
- msg->addF32Fast(_PREHASH_West, west );
- msg->addF32Fast(_PREHASH_South, south );
- msg->addF32Fast(_PREHASH_East, east );
- msg->addF32Fast(_PREHASH_North, north );
- msg->addBOOL("SnapSelection", FALSE );
- msg->sendReliable( region->getHost() );
+ // if (!request_properties) last_south and last_west will be equal to new values
+ }
+
+ if (request_properties)
+ {
+ last_west = west_parcel_step;
+ last_south = south_parcel_step;
+ last_region = region_id;
- mHoverRequestResult = PARCEL_RESULT_NO_DATA;
+ LL_DEBUGS("ParcelMgr") << "Requesting parcel properties on hover, for " << pos << LL_ENDL;
+
+
+ // Send a rectangle around the point.
+ // This means the parcel sent back is at least a rectangle around the point,
+ // which is more efficient for public land. Fewer requests are sent. JC
+ F32 west = PARCEL_GRID_STEP_METERS * floor(pos_in_region.mV[VX] / PARCEL_GRID_STEP_METERS);
+ F32 south = PARCEL_GRID_STEP_METERS * floor(pos_in_region.mV[VY] / PARCEL_GRID_STEP_METERS);
+
+ F32 east = west + PARCEL_GRID_STEP_METERS;
+ F32 north = south + PARCEL_GRID_STEP_METERS;
+
+ // Send request message
+ LLMessageSystem *msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_ParcelPropertiesRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_ParcelData);
+ msg->addS32Fast(_PREHASH_SequenceID, HOVERED_PARCEL_SEQ_ID);
+ msg->addF32Fast(_PREHASH_West, west);
+ msg->addF32Fast(_PREHASH_South, south);
+ msg->addF32Fast(_PREHASH_East, east);
+ msg->addF32Fast(_PREHASH_North, north);
+ msg->addBOOL("SnapSelection", FALSE);
+ msg->sendReliable(region->getHost());
+
+ mHoverRequestResult = PARCEL_RESULT_NO_DATA;
+ }
}
@@ -1472,7 +1527,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
if (request_result == PARCEL_RESULT_NO_DATA)
{
// no valid parcel data
- LL_INFOS() << "no valid parcel data" << LL_ENDL;
+ LL_INFOS("ParcelMgr") << "no valid parcel data" << LL_ENDL;
return;
}
@@ -1504,7 +1559,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
}
else
{
- LL_INFOS() << "out of order agent parcel sequence id " << sequence_id
+ LL_INFOS("ParcelMgr") << "out of order agent parcel sequence id " << sequence_id
<< " last good " << parcel_mgr.mAgentParcelSequenceID
<< LL_ENDL;
return;
@@ -1552,6 +1607,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
msg->getS32("ParcelData", "OtherCleanTime", other_clean_time );
+ LL_DEBUGS("ParcelMgr") << "Processing parcel " << local_id << " update, target(sequence): " << sequence_id << LL_ENDL;
+
// Actually extract the data.
if (parcel)
{
@@ -1790,7 +1847,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
}
else
{
- LL_INFOS() << "Stopping parcel music (invalid audio stream URL)" << LL_ENDL;
+ LL_INFOS("ParcelMgr") << "Stopping parcel music (invalid audio stream URL)" << LL_ENDL;
// clears the URL
// null value causes fade out
LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
@@ -1798,7 +1855,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
}
else if (!gAudiop->getInternetStreamURL().empty())
{
- LL_INFOS() << "Stopping parcel music (parcel stream URL is empty)" << LL_ENDL;
+ LL_INFOS("ParcelMgr") << "Stopping parcel music (parcel stream URL is empty)" << LL_ENDL;
// null value causes fade out
LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
}
@@ -1827,7 +1884,7 @@ void LLViewerParcelMgr::optionally_start_music(const std::string& music_url)
gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) &&
gSavedSettings.getBOOL("MediaTentativeAutoPlay")))
{
- LL_INFOS() << "Starting parcel music " << music_url << LL_ENDL;
+ LL_INFOS("ParcelMgr") << "Starting parcel music " << music_url << LL_ENDL;
LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(music_url);
}
else
@@ -1855,7 +1912,7 @@ void LLViewerParcelMgr::processParcelAccessListReply(LLMessageSystem *msg, void
if (parcel_id != parcel->getLocalID())
{
- LL_WARNS_ONCE("") << "processParcelAccessListReply for parcel " << parcel_id
+ LL_WARNS_ONCE("ParcelMgr") << "processParcelAccessListReply for parcel " << parcel_id
<< " which isn't the selected parcel " << parcel->getLocalID()<< LL_ENDL;
return;
}
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index 4fd423b6f4..7c3dd00e1a 100644
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -274,6 +274,23 @@ U8 LLViewerParcelOverlay::ownership( const LLVector3& pos) const
return ownership(row, column);
}
+U8 LLViewerParcelOverlay::parcelLineFlags(const LLVector3& pos) const
+{
+ S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
+ S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
+ return parcelLineFlags(row, column);
+}
+U8 LLViewerParcelOverlay::parcelLineFlags(S32 row, S32 col) const
+{
+ U8 flags = PARCEL_WEST_LINE | PARCEL_SOUTH_LINE;
+ if (row > mParcelGridsPerEdge || col > mParcelGridsPerEdge)
+ {
+ LL_WARNS() << "Attempted to get ownership out of region's overlay, row: " << row << " col: " << col << LL_ENDL;
+ return flags;
+ }
+ return mOwnership[row * mParcelGridsPerEdge + col] & flags;
+}
+
F32 LLViewerParcelOverlay::getOwnedRatio() const
{
S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h
index 14a2af5354..e30dbf17b3 100644
--- a/indra/newview/llviewerparceloverlay.h
+++ b/indra/newview/llviewerparceloverlay.h
@@ -71,6 +71,8 @@ public:
S32 renderPropertyLines();
U8 ownership( const LLVector3& pos) const;
+ U8 parcelLineFlags( const LLVector3& pos) const;
+ U8 parcelLineFlags(S32 row, S32 col) const;
// MANIPULATE
void uncompressLandOverlay(S32 chunk, U8 *compressed_overlay);
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index ba733bb068..0d7e295b9a 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -44,6 +44,7 @@
#include "llagent.h"
#include "llagentcamera.h"
+#include "llappviewer.h"
#include "llavatarrenderinfoaccountant.h"
#include "llcallingcard.h"
#include "llcommandhandler.h"
@@ -105,6 +106,18 @@ typedef std::map<std::string, std::string> CapabilityMap;
static void log_capabilities(const CapabilityMap &capmap);
+namespace
+{
+
+void newRegionEntry(LLViewerRegion& region)
+{
+ LL_INFOS("LLViewerRegion") << "Entering region [" << region.getName() << "]" << LL_ENDL;
+ gDebugInfo["CurrentRegion"] = region.getName();
+ LLAppViewer::instance()->writeDebugInfo();
+}
+
+} // anonymous namespace
+
// support for secondlife:///app/region/{REGION} SLapps
// N.B. this is defined to work exactly like the classic secondlife://{REGION}
// However, the later syntax cannot support spaces in the region name because
@@ -252,6 +265,9 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
return; // this error condition is not recoverable.
}
+ // record that we just entered a new region
+ newRegionEntry(*regionp);
+
// After a few attempts, continue login. But keep trying to get the caps:
if (mSeedCapAttempts >= mSeedCapMaxAttemptsBeforeLogin &&
STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
@@ -375,6 +391,9 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle)
break; // this error condition is not recoverable.
}
+ // record that we just entered a new region
+ newRegionEntry(*regionp);
+
LLSD capabilityNames = LLSD::emptyArray();
buildCapabilityNames(capabilityNames);
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index ff7647a7e4..f610335b07 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -399,7 +399,8 @@ void LLViewerShaderMgr::setShaders()
return;
}
- LLGLSLShader::sIndexedTextureChannels = llmax(llmin(gGLManager.mNumTextureImageUnits, (S32) gSavedSettings.getU32("RenderMaxTextureIndex")), 1);
+ static LLCachedControl<U32> max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16);
+ LLGLSLShader::sIndexedTextureChannels = llmax(llmin(gGLManager.mNumTextureImageUnits, (S32) max_texture_index), 1);
//NEVER use more than 16 texture channels (work around for prevalent driver bug)
LLGLSLShader::sIndexedTextureChannels = llmin(LLGLSLShader::sIndexedTextureChannels, 16);
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 41da58f94f..2c16c3c942 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -100,7 +100,7 @@ const S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128;
const S32 DEFAULT_ICON_DIMENTIONS = 32;
S32 LLViewerTexture::sMinLargeImageSize = 65536; //256 * 256.
S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA;
-BOOL LLViewerTexture::sFreezeImageScalingDown = FALSE;
+bool LLViewerTexture::sFreezeImageUpdates = false;
F32 LLViewerTexture::sCurrentTime = 0.0f;
F32 LLViewerTexture::sTexelPixelRatio = 1.0f;
@@ -474,6 +474,7 @@ void LLViewerTexture::initClass()
// tuning params
const F32 discard_bias_delta = .25f;
const F32 discard_delta_time = 0.5f;
+const F32 GPU_MEMORY_CHECK_WAIT_TIME = 1.0f;
// non-const (used externally
F32 texmem_lower_bound_scale = 0.85f;
F32 texmem_middle_bound_scale = 0.925f;
@@ -483,53 +484,68 @@ static LLTrace::BlockTimerStatHandle FTM_TEXTURE_MEMORY_CHECK("Memory Check");
//static
bool LLViewerTexture::isMemoryForTextureLow()
{
- const F32 WAIT_TIME = 1.0f; //second
- static LLFrameTimer timer;
+ // Note: we need to figure out a better source for 'min' values,
+ // what is free for low end at minimal settings is 'nothing left'
+ // for higher end gpus at high settings.
+ const S32Megabytes MIN_FREE_TEXTURE_MEMORY(20);
+ const S32Megabytes MIN_FREE_MAIN_MEMORY(100);
- if(timer.getElapsedTimeF32() < WAIT_TIME) //call this once per second.
- {
- return false;
- }
- timer.reset();
+ S32Megabytes gpu;
+ S32Megabytes physical;
+ getGPUMemoryForTextures(gpu, physical);
- LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK);
+ return (gpu < MIN_FREE_TEXTURE_MEMORY) || (physical < MIN_FREE_MAIN_MEMORY);
+}
- const S32Megabytes MIN_FREE_TEXTURE_MEMORY(20); //MB Changed to 20 MB per MAINT-6882
- const S32Megabytes MIN_FREE_MAIN_MEMORY(100); //MB
+//static
+bool LLViewerTexture::isMemoryForTextureSuficientlyFree()
+{
+ const S32Megabytes DESIRED_FREE_TEXTURE_MEMORY(50);
+ const S32Megabytes DESIRED_FREE_MAIN_MEMORY(200);
- bool low_mem = false;
- if (gGLManager.mHasATIMemInfo)
- {
- S32 meminfo[4];
- glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
+ S32Megabytes gpu;
+ S32Megabytes physical;
+ getGPUMemoryForTextures(gpu, physical);
- if((S32Megabytes)meminfo[0] < MIN_FREE_TEXTURE_MEMORY)
- {
- low_mem = true;
- }
+ return (gpu > DESIRED_FREE_TEXTURE_MEMORY) && (physical > DESIRED_FREE_MAIN_MEMORY);
+}
- if(!low_mem) //check main memory, only works for windows.
- {
- LLMemory::updateMemoryInfo();
- if(LLMemory::getAvailableMemKB() < MIN_FREE_TEXTURE_MEMORY)
- {
- low_mem = true;
- }
- }
- }
- //Enabled this branch per MAINT-6882
- else if (gGLManager.mHasNVXMemInfo)
- {
- S32 free_memory;
- glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory);
-
- if ((S32Megabytes)(free_memory / 1024) < MIN_FREE_TEXTURE_MEMORY)
- {
- low_mem = true;
- }
- }
+//static
+void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical)
+{
+ static LLFrameTimer timer;
+ static S32Megabytes gpu_res = S32Megabytes(S32_MAX);
+ static S32Megabytes physical_res = S32Megabytes(S32_MAX);
+
+ if (timer.getElapsedTimeF32() < GPU_MEMORY_CHECK_WAIT_TIME) //call this once per second.
+ {
+ gpu = gpu_res;
+ physical = physical_res;
+ return;
+ }
+ timer.reset();
+
+ LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK);
+
+ if (gGLManager.mHasATIMemInfo)
+ {
+ S32 meminfo[4];
+ glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
+ gpu_res = (S32Megabytes)meminfo[0];
+
+ //check main memory, only works for windows.
+ LLMemory::updateMemoryInfo();
+ physical_res = LLMemory::getAvailableMemKB();
+ }
+ else if (gGLManager.mHasNVXMemInfo)
+ {
+ S32 free_memory;
+ glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory);
+ gpu_res = (S32Megabytes)(free_memory / 1024);
+ }
- return low_mem;
+ gpu = gpu_res;
+ physical = physical_res;
}
static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_MEDIA("Media");
@@ -572,15 +588,20 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity
sEvaluationTimer.reset();
}
}
- else if(sEvaluationTimer.getElapsedTimeF32() > discard_delta_time && isMemoryForTextureLow())
+ else if(isMemoryForTextureLow())
{
- sDesiredDiscardBias += discard_bias_delta;
- sEvaluationTimer.reset();
+ // Note: isMemoryForTextureLow() uses 1s delay, make sure we waited enough for it to recheck
+ if (sEvaluationTimer.getElapsedTimeF32() > GPU_MEMORY_CHECK_WAIT_TIME)
+ {
+ sDesiredDiscardBias += discard_bias_delta;
+ sEvaluationTimer.reset();
+ }
}
- else if (sDesiredDiscardBias > 0.0f &&
- sBoundTextureMemory < sMaxBoundTextureMemory * texmem_lower_bound_scale &&
- sTotalTextureMemory < sMaxTotalTextureMem * texmem_lower_bound_scale)
- {
+ else if (sDesiredDiscardBias > 0.0f
+ && sBoundTextureMemory < sMaxBoundTextureMemory * texmem_lower_bound_scale
+ && sTotalTextureMemory < sMaxTotalTextureMem * texmem_lower_bound_scale
+ && isMemoryForTextureSuficientlyFree())
+ {
// If we are using less texture memory than we should,
// scale down the desired discard level
if (sEvaluationTimer.getElapsedTimeF32() > discard_delta_time)
@@ -590,14 +611,8 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity
}
}
sDesiredDiscardBias = llclamp(sDesiredDiscardBias, desired_discard_bias_min, desired_discard_bias_max);
-
- F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed();
- F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed();
- sCameraMovingBias = llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1);
- sCameraMovingDiscardBias = (S8)(sCameraMovingBias);
- LLViewerTexture::sFreezeImageScalingDown = (sBoundTextureMemory < 0.75f * sMaxBoundTextureMemory * texmem_middle_bound_scale) &&
- (sTotalTextureMemory < 0.75f * sMaxTotalTextureMem * texmem_middle_bound_scale);
+ LLViewerTexture::sFreezeImageUpdates = sDesiredDiscardBias > (desired_discard_bias_max - 1.0f);
}
//end of static functions
@@ -3117,9 +3132,9 @@ S8 LLViewerLODTexture::getType() const
return LLViewerTexture::LOD_TEXTURE;
}
-BOOL LLViewerLODTexture::isUpdateFrozen()
+bool LLViewerLODTexture::isUpdateFrozen()
{
- return LLViewerTexture::sFreezeImageScalingDown && !getDiscardLevel();
+ return LLViewerTexture::sFreezeImageUpdates;
}
// This is gauranteed to get called periodically for every texture
@@ -3245,9 +3260,16 @@ void LLViewerLODTexture::processTextureStats()
(!getBoundRecently() || mDesiredDiscardLevel >= mCachedRawDiscardLevel))
{
scaleDown();
-
}
}
+
+ if (isUpdateFrozen() // we are out of memory and nearing max allowed bias
+ && mBoostLevel < LLGLTexture::BOOST_SCULPTED
+ && mDesiredDiscardLevel < current_discard)
+ {
+ // stop requesting more
+ mDesiredDiscardLevel = current_discard;
+ }
}
if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0)
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 5d89f9f029..7cbcc931b1 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -186,6 +186,9 @@ private:
virtual void switchToCachedImage();
static bool isMemoryForTextureLow() ;
+ static bool isMemoryForTextureSuficientlyFree();
+ static void getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical);
+
protected:
LLUUID mID;
S32 mTextureListType; // along with mID identifies where to search for this texture in TextureList
@@ -227,7 +230,7 @@ public:
static S32 sMaxSculptRez ;
static S32 sMinLargeImageSize ;
static S32 sMaxSmallImageSize ;
- static BOOL sFreezeImageScalingDown ;//do not scale down image res if set.
+ static bool sFreezeImageUpdates;
static F32 sCurrentTime ;
enum EDebugTexels
@@ -543,7 +546,7 @@ public:
/*virtual*/ S8 getType() const;
// Process image stats to determine priority/quality requirements.
/*virtual*/ void processTextureStats();
- BOOL isUpdateFrozen() ;
+ bool isUpdateFrozen() ;
private:
void init(bool firstinit) ;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index e53ccd7b8d..0f086711d9 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -306,6 +306,9 @@ private:
RecordToChatConsole::RecordToChatConsole():
mRecorder(new RecordToChatConsoleRecorder())
{
+ mRecorder->showTags(false);
+ mRecorder->showLocation(false);
+ mRecorder->showMultiline(true);
}
////////////////////////////////////////////////////////////////////////////
@@ -3845,7 +3848,7 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls,
BOOL draw_handles = TRUE;
- if (tool == LLToolCompTranslate::getInstance() && !all_selected_objects_move)
+ if (tool == LLToolCompTranslate::getInstance() && !all_selected_objects_move && !LLSelectMgr::getInstance()->isSelfAvatarSelected())
{
draw_handles = FALSE;
}
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 321f774210..2682c5b698 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -5992,7 +5992,7 @@ void LLVOAvatar::rebuildAttachmentOverrides()
LLViewerObject *vo = *at_it;
// Attached animated objects affect joints in their control
// avs, not the avs to which they are attached.
- if (!vo->isAnimatedObject())
+ if (vo && !vo->isAnimatedObject())
{
addAttachmentOverridesForObject(vo);
}
@@ -6043,7 +6043,7 @@ void LLVOAvatar::updateAttachmentOverrides()
LLViewerObject *vo = *at_it;
// Attached animated objects affect joints in their control
// avs, not the avs to which they are attached.
- if (!vo->isAnimatedObject())
+ if (vo && !vo->isAnimatedObject())
{
addAttachmentOverridesForObject(vo, &meshes_seen);
}
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index deb22617a4..a4f8e95c65 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -75,6 +75,8 @@ class LLTexGlobalColor;
struct LLAppearanceMessageContents;
class LLViewerJointMesh;
+const F32 MAX_AVATAR_LOD_FACTOR = 1.0f;
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLVOAvatar
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index ee333bcee2..cf40058c34 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -770,14 +770,13 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()
{
#ifndef VIVOXDAEMON_REMOTEHOST
// Launch the voice daemon
- std::string exe_path = gDirUtilp->getExecutableDir();
- exe_path += gDirUtilp->getDirDelimiter();
+ std::string exe_path = gDirUtilp->getAppRODataDir();
#if LL_WINDOWS
- exe_path += "SLVoice.exe";
+ gDirUtilp->append(exe_path, "SLVoice.exe");
#elif LL_DARWIN
- exe_path += "../Resources/SLVoice";
+ gDirUtilp->append(exe_path, "SLVoice");
#else
- exe_path += "SLVoice";
+ gDirUtilp->append(exe_path, "SLVoice");
#endif
// See if the vivox executable exists
llstat s;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 24726e61e8..3c487a112e 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1380,7 +1380,8 @@ BOOL LLVOVolume::calcLOD()
mLODDistance = distance;
mLODRadius = radius;
- if (gSavedSettings.getBOOL("DebugObjectLODs"))
+ static LLCachedControl<bool> debug_lods(gSavedSettings, "DebugObjectLODs", false);
+ if (debug_lods)
{
if (getAvatar() && isRootEdit())
{
@@ -4276,10 +4277,16 @@ F32 LLVOVolume::getBinRadius()
F32 scale = 1.f;
- S32 size_factor = llmax(gSavedSettings.getS32("OctreeStaticObjectSizeFactor"), 1);
- S32 attachment_size_factor = llmax(gSavedSettings.getS32("OctreeAttachmentSizeFactor"), 1);
- LLVector3 distance_factor = gSavedSettings.getVector3("OctreeDistanceFactor");
- LLVector3 alpha_distance_factor = gSavedSettings.getVector3("OctreeAlphaDistanceFactor");
+ static LLCachedControl<S32> octree_size_factor(gSavedSettings, "OctreeStaticObjectSizeFactor", 3);
+ static LLCachedControl<S32> octree_attachment_size_factor(gSavedSettings, "OctreeAttachmentSizeFactor", 4);
+ static LLCachedControl<LLVector3> octree_distance_factor(gSavedSettings, "OctreeDistanceFactor", LLVector3(0.01f, 0.f, 0.f));
+ static LLCachedControl<LLVector3> octree_alpha_distance_factor(gSavedSettings, "OctreeAlphaDistanceFactor", LLVector3(0.1f, 0.f, 0.f));
+
+ S32 size_factor = llmax((S32)octree_size_factor, 1);
+ S32 attachment_size_factor = llmax((S32)octree_attachment_size_factor, 1);
+ LLVector3 distance_factor = octree_distance_factor;
+ LLVector3 alpha_distance_factor = octree_alpha_distance_factor;
+
const LLVector4a* ext = mDrawable->getSpatialExtents();
BOOL shrink_wrap = mDrawable->isAnimating();
@@ -5352,8 +5359,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
U32 useage = group->getSpatialPartition()->mBufferUsage;
- U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask);
- U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask);
+ LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512);
+ LLCachedControl<S32> max_node_size(gSavedSettings, "RenderMaxNodeSize", 65536);
+ U32 max_vertices = (max_vbo_size * 1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask);
+ U32 max_total = (max_node_size * 1024) / LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask);
max_vertices = llmin(max_vertices, (U32) 65535);
U32 cur_total = 0;
@@ -6106,7 +6115,8 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
#endif
//calculate maximum number of vertices to store in a single buffer
- U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask);
+ LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512);
+ U32 max_vertices = (max_vbo_size * 1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask);
max_vertices = llmin(max_vertices, (U32) 65535);
{
@@ -6149,7 +6159,8 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels;
}
- texture_index_channels = llmin(texture_index_channels, (S32) gSavedSettings.getU32("RenderMaxTextureIndex"));
+ static LLCachedControl<U32> max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16);
+ texture_index_channels = llmin(texture_index_channels, (S32) max_texture_index);
//NEVER use more than 16 texture index channels (workaround for prevalent driver bug)
texture_index_channels = llmin(texture_index_channels, 16);
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 0882fc095d..13db9c39b7 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -54,6 +54,8 @@ enum LLVolumeInterfaceType
INTERFACE_FLEXIBLE = 1,
};
+const F32 MAX_LOD_FACTOR = 4.0f;
+
class LLRiggedVolume : public LLVolume
{
diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp
index 3b9b96e9f1..2cb5fc81b0 100644
--- a/indra/newview/llvowlsky.cpp
+++ b/indra/newview/llvowlsky.cpp
@@ -335,7 +335,8 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
}
{
- const U32 max_buffer_bytes = gSavedSettings.getS32("RenderMaxVBOSize")*1024;
+ LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512);
+ const U32 max_buffer_bytes = max_vbo_size * 1024;
const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK;
const U32 max_verts = max_buffer_bytes / LLVertexBuffer::calcVertexSize(data_mask);
diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp
index 2782cd9545..dd6c77ca7d 100644
--- a/indra/newview/llwatchdog.cpp
+++ b/indra/newview/llwatchdog.cpp
@@ -155,7 +155,7 @@ void LLWatchdogTimeout::ping(const std::string& state)
// LLWatchdog
LLWatchdog::LLWatchdog() :
- mSuspectsAccessMutex(NULL),
+ mSuspectsAccessMutex(),
mTimer(NULL),
mLastClockCount(0),
mKillerCallback(&default_killer_callback)
@@ -185,7 +185,7 @@ void LLWatchdog::init(killer_event_callback func)
mKillerCallback = func;
if(!mSuspectsAccessMutex && !mTimer)
{
- mSuspectsAccessMutex = new LLMutex(NULL);
+ mSuspectsAccessMutex = new LLMutex();
mTimer = new LLWatchdogTimerThread();
mTimer->setSleepTime(WATCHDOG_SLEEP_TIME_USEC / 1000);
mLastClockCount = LLTimer::getTotalTime();
diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp
index 81d4e30a7a..8dcef2c7cd 100644
--- a/indra/newview/llwebprofile.cpp
+++ b/indra/newview/llwebprofile.cpp
@@ -33,6 +33,7 @@
#include "llimagepng.h"
#include "llsdserialize.h"
+#include "llstring.h"
// newview
#include "llpanelprofile.h" // for getProfileURL(). FIXME: move the method to LLAvatarActions
@@ -264,6 +265,5 @@ void LLWebProfile::reportImageUploadStatus(bool ok)
std::string LLWebProfile::getAuthCookie()
{
// This is needed to test image uploads on Linux viewer built with OpenSSL 1.0.0 (0.9.8 works fine).
- const char* debug_cookie = getenv("LL_SNAPSHOT_COOKIE");
- return debug_cookie ? debug_cookie : sAuthCookie;
+ return LLStringUtil::getenv("LL_SNAPSHOT_COOKIE", sAuthCookie);
}
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 707fe76cef..f1c23bdb2d 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -465,7 +465,11 @@ void LLWorldMapView::draw()
mesg, 0,
llfloor(left + 3), llfloor(bottom + 2),
LLColor4::white,
- LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW);
+ LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW,
+ S32_MAX, //max_chars
+ sMapScale, //max_pixels
+ NULL,
+ TRUE); //use ellipses
}
}
}
@@ -1751,9 +1755,12 @@ BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask )
case MAP_ITEM_LAND_FOR_SALE_ADULT:
{
LLVector3d pos_global = viewPosToGlobal(x, y);
- LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global);
- LLFloaterReg::hideInstance("world_map");
- LLFloaterReg::showInstance("search", LLSD().with("category", "land").with("query", info->getName()));
+ std::string sim_name;
+ if (LLWorldMap::getInstance()->simNameFromPosGlobal(pos_global, sim_name))
+ {
+ LLFloaterReg::hideInstance("world_map");
+ LLFloaterReg::showInstance("search", LLSD().with("category", "land").with("query", sim_name));
+ }
break;
}
case MAP_ITEM_CLASSIFIED:
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index 143c97fca4..8e2539606b 100644
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -362,6 +362,10 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const
{
httpOpts->setRetries(httpParams["retries"].asInteger());
}
+ if (httpParams.has("DNSCacheTimeout"))
+ {
+ httpOpts->setDNSCacheTimeout(httpParams["DNSCacheTimeout"].asInteger());
+ }
bool vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
mCertStore = gSavedSettings.getString("CertStore");
@@ -483,38 +487,24 @@ void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status)
{
CURLcode code = static_cast<CURLcode>(status.toULong());
std::string message;
- std::string uri = "http://secondlife.com/community/support.php";
+ std::string uri = "http://support.secondlife.com";
LLURI failuri(mURI);
-
+ LLStringUtil::format_map_t args;
switch (code)
{
case CURLE_COULDNT_RESOLVE_HOST:
- message =
- std::string("DNS could not resolve the host name(") + failuri.hostName() + ").\n"
- "Please verify that you can connect to the www.secondlife.com\n"
- "web site. If you can, but continue to receive this error,\n"
- "please go to the support section and report this problem.";
+ args["[HOSTNAME]"] = failuri.hostName();
+ message = LLTrans::getString("couldnt_resolve_host", args);
break;
case CURLE_SSL_PEER_CERTIFICATE:
- message =
- "The login server couldn't verify itself via SSL.\n"
- "If you continue to receive this error, please go\n"
- "to the Support section of the SecondLife.com web site\n"
- "and report the problem.";
+ message = LLTrans::getString("ssl_peer_certificate");
break;
case CURLE_SSL_CACERT:
- case CURLE_SSL_CONNECT_ERROR:
- message =
- "Often this means that your computer\'s clock is set incorrectly.\n"
- "Please go to Control Panels and make sure the time and date\n"
- "are set correctly.\n"
- "Also check that your network and firewall are set up correctly.\n"
- "If you continue to receive this error, please go\n"
- "to the Support section of the SecondLife.com web site\n"
- "and report the problem.";
+ case CURLE_SSL_CONNECT_ERROR:
+ message = LLTrans::getString("ssl_connect_error");
break;
default:
diff --git a/indra/newview/skins/default/default_languages.xml b/indra/newview/skins/default/default_languages.xml
new file mode 100644
index 0000000000..357930e1c5
--- /dev/null
+++ b/indra/newview/skins/default/default_languages.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<labels>
+ <label
+ name="en"
+ value="System default" />
+ <label
+ name="it"
+ value="Default di sistema" />
+ <label
+ name="ja"
+ value="システムデフォルト" />
+ <label
+ name="pl"
+ value="Domyślny" />
+ <label
+ name="pt"
+ value="Padrão" />
+ <label
+ name="ru"
+ value="Язык ÑиÑтемы" />
+ <label
+ name="tr"
+ value="Sistem varsayılanı" />
+ <label
+ name="zh"
+ value="系統é è¨­" />
+ <label
+ name="da"
+ value="System standard" />
+ <label
+ name="de"
+ value="Systemvorgabe" />
+ <label
+ name="es"
+ value="Predeterminado del sistema" />
+ <label
+ name="fr"
+ value="Choix par défaut" />
+</labels>
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_general.xml b/indra/newview/skins/default/xui/da/panel_preferences_general.xml
index 5702d48e97..624c6634cc 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_general.xml
@@ -4,7 +4,6 @@
Sprog:
</text>
<combo_box name="language_combobox">
- <combo_box.item label="System standard" name="System Default Language"/>
<combo_box.item label="English (Engelsk)" name="English"/>
<combo_box.item label="Dansk - Beta" name="Danish"/>
<combo_box.item label="Deutsch (Tysk) - Beta" name="Deutsch(German)"/>
diff --git a/indra/newview/skins/default/xui/de/floater_pathfinding_console.xml b/indra/newview/skins/default/xui/de/floater_pathfinding_console.xml
index 27c6b73967..2422e414e0 100644
--- a/indra/newview/skins/default/xui/de/floater_pathfinding_console.xml
+++ b/indra/newview/skins/default/xui/de/floater_pathfinding_console.xml
@@ -96,7 +96,7 @@
</combo_box>
<check_box label="Begehbare Objekte" name="show_walkables"/>
<check_box label="Materialvolumen" name="show_material_volumes"/>
- <check_box label="Statische Hinternisse" name="show_static_obstacles"/>
+ <check_box label="Statische Hindernisse" name="show_static_obstacles"/>
<check_box label="Ausschlussvolumen" name="show_exclusion_volumes"/>
<check_box label="Wasserebene" name="show_water_plane"/>
<check_box label="Mit Röntgenblick" name="show_xray"/>
diff --git a/indra/newview/skins/default/xui/de/floater_pathfinding_linksets.xml b/indra/newview/skins/default/xui/de/floater_pathfinding_linksets.xml
index a423f3efea..6729e242ac 100644
--- a/indra/newview/skins/default/xui/de/floater_pathfinding_linksets.xml
+++ b/indra/newview/skins/default/xui/de/floater_pathfinding_linksets.xml
@@ -61,10 +61,10 @@
Begehbar
</floater.string>
<floater.string name="linkset_use_static_obstacle">
- Statisches Hinternis
+ Statisches Hindernis
</floater.string>
<floater.string name="linkset_use_dynamic_obstacle">
- Bewegliches Hinternis
+ Bewegliches Hindernis
</floater.string>
<floater.string name="linkset_use_material_volume">
Materialvolumen
@@ -103,8 +103,8 @@
<combo_box name="filter_by_linkset_use">
<combo_box.item label="Nach Linkset-Nutzung filtern..." name="filter_by_linkset_use_none"/>
<combo_box.item label="Begehbar" name="filter_by_linkset_use_walkable"/>
- <combo_box.item label="Statisches Hinternis" name="filter_by_linkset_use_static_obstacle"/>
- <combo_box.item label="Bewegliches Hinternis" name="filter_by_linkset_use_dynamic_obstacle"/>
+ <combo_box.item label="Statisches Hindernis" name="filter_by_linkset_use_static_obstacle"/>
+ <combo_box.item label="Bewegliches Hindernis" name="filter_by_linkset_use_dynamic_obstacle"/>
<combo_box.item label="Materialvolumen" name="filter_by_linkset_use_material_volume"/>
<combo_box.item label="Ausschlussvolumen" name="filter_by_linkset_use_exclusion_volume"/>
<combo_box.item label="Bewegliches Phantom" name="filter_by_linkset_use_dynamic_phantom"/>
diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml
index 43af1d8655..57dbaa0ea6 100644
--- a/indra/newview/skins/default/xui/de/notifications.xml
+++ b/indra/newview/skins/default/xui/de/notifications.xml
@@ -244,6 +244,10 @@ Wählen Sie ein einzelnes Objekt aus und versuchen Sie es erneut.
Hinweis: Bei Aktivierung dieser Option sehen alle Personen, die diesen Computer benutzen, Ihre Lieblingsorte.
<usetemplate name="okbutton" yestext="OK"/>
</notification>
+ <notification name="AllowMultipleViewers">
+ Das Starten mehrerer Second Life Viewer wird nicht unterstützt. Dies kann zu Kollisionen des Textur-Caches, Fehlern sowie verschlechterter Grafik und Leistung führen.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="GrantModifyRights">
Wenn Sie einem anderen Einwohner Änderungsrechte gewähren, dann kann dieser JEDES Objekt, das Sie inworld besitzen, ändern, löschen oder an sich nehmen. Seien Sie daher beim Gewähren dieser Rechte sehr vorsichtig!
Möchten Sie [NAME] Änderungsrechte gewähren?
@@ -725,9 +729,9 @@ Sie können die Grafikqualität unter Einstellungen &gt; Grafik wieder erhöhen.
Sie sind nicht zum Terraformen der Parzelle „[PARCEL]“ berechtigt.
</notification>
<notification name="CannotCopyWarning">
- Sie sind nicht berechtigt, die folgenden Objekte zu kopieren:
-[ITEMS]
-Wenn Sie diese weitergeben, werden sie aus Ihrem Inventar entfernt. Möchten Sie diese Objekte wirklich weggeben?
+ Sie sind nicht berechtigt, die folgenden Objekte zu kopieren:
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
+und die Objekte werden aus Ihrem Inventar gelöscht, wenn Sie diese weggeben. Möchten Sie diese Objekte wirklich weggeben?
<usetemplate name="okcancelbuttons" notext="Nein" yestext="Ja"/>
</notification>
<notification name="CannotGiveItem">
@@ -3730,13 +3734,13 @@ es sich nicht in der gleichen Region befindet wie Sie.
Auf Land, das Sie nicht besitzen, können Sie keine Bäume und Gräser erstellen.
</notification>
<notification name="NoCopyPermsNoObject">
- Kopieren fehlgeschlagen, da Sie keine Berechtigung zum Kopieren des Objekts „OBJ_NAME]“ besitzen.
+ Kopieren fehlgeschlagen, da Sie nicht über die Berechtigung zum Kopieren des Objekts &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; verfügen.
</notification>
<notification name="NoTransPermsNoObject">
- Kopieren fehlgeschlagen, weil Objekt „[OBJ_NAME]“ nicht an Sie übertragen werden kann.
+ Kopieren fehlgeschlagen, da das Objekt &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nicht an Sie übertragen werden kann.
</notification>
<notification name="AddToNavMeshNoCopy">
- Kopieren fehlgeschlagen, weil Objekt „[OBJ_NAME]“ zum Navmesh beiträgt.
+ Kopieren fehlgeschlagen, da das Objekt &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; zum Navmesh beiträgt.
</notification>
<notification name="DupeWithNoRootsSelected">
Ohne ausgewählte Hauptobjekte duplizieren.
@@ -3781,34 +3785,34 @@ Warten Sie kurz und versuchen Sie es noch einmal.
Erneutes Speichern im Inventar ist deaktiviert.
</notification>
<notification name="NoExistNoSaveToContents">
- „[OBJ_NAME]“ kann nicht im Objektinhalt gespeichert werden, da das Objekt, aus dem es gerezzt wurde, nicht mehr existiert.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; kann nicht im Objektinhalt gespeichert werden, da das Objekt, aus dem es gerezzt wurde, nicht mehr existiert.
</notification>
<notification name="NoModNoSaveToContents">
- „[OBJ_NAME]“ kann nicht in Objektinhalt gespeichert werden, da Sie nicht die Berechtigung zum Modifizieren des Objekts „[DEST_NAME]“ besitzen.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; kann nicht in Objektinhalt gespeichert werden, da Sie nicht über die Berechtigung zum Modifizieren des Objekts &lt;nolink&gt;&apos;[DEST_NAME]&apos;&lt;/nolink&gt; verfügen.
</notification>
<notification name="NoSaveBackToInvDisabled">
- „[OBJ_NAME]“ kann nicht erneut im Inventar gespeichert werden – dieser Vorgang wurde deaktiviert.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; kann nicht erneut im Inventar gespeichert werden – dieser Vorgang wurde deaktiviert.
</notification>
<notification name="NoCopyNoSelCopy">
- Sie können Ihre Auswahl nicht kopieren, da Sie nicht die Berechtigung zum Kopieren des Objekts „[OBJ_NAME]“ haben.
+ Sie können Ihre Auswahl nicht kopieren, da Sie nicht über die Berechtigung zum Kopieren des Objekts &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; verfügen.
</notification>
<notification name="NoTransNoSelCopy">
- Sie können Ihre Auswahl nicht kopieren, da das Objekt „[OBJ_NAME]“ nicht übertragbar ist.
+ Sie können Ihre Auswahl nicht kopieren, da das Objekt &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nicht übertragbar ist.
</notification>
<notification name="NoTransNoCopy">
- Sie können Ihre Auswahl nicht kopieren, da das Objekt „[OBJ_NAME]“ nicht übertragbar ist.
+ Sie können Ihre Auswahl nicht kopieren, da das Objekt &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nicht übertragbar ist.
</notification>
<notification name="NoPermsNoRemoval">
- Entfernen des Objekts „[OBJ_NAME]“ aus dem Simulator wird vom Berechtigungssystem nicht gestattet.
+ Entfernen des Objekts &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; aus dem Simulator wird vom Berechtigungssystem nicht gestattet.
</notification>
<notification name="NoModNoSaveSelection">
- Sie können Ihre Auswahl nicht speichern, da Sie keine Berechtigung zum Modifizieren des Objekts „[OBJ_NAME]“ besitzen.
+ Sie können Ihre Auswahl nicht speichern, da Sie nicht über die Berechtigung zum Modifizieren des Objekts &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; verfügen.
</notification>
<notification name="NoCopyNoSaveSelection">
- Ihre Auswahl kann nicht gespeichert werden, da das Objekt „[OBJ_NAME]“ nicht kopiert werden kann.
+ Ihre Auswahl kann nicht gespeichert werden, da das Objekt &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nicht kopiert werden kann.
</notification>
<notification name="NoModNoTaking">
- Sie können Ihre Auswahl nicht in Empfang nehmen, da Sie nicht die Berechtigung zum Modifizieren des Objekts „[OBJ_NAME]“ haben.
+ Sie können Ihre Auswahl nicht in Empfang nehmen, da Sie nicht über die Berechtigung zum Modifizieren des Objekts &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; verfügen.
</notification>
<notification name="RezDestInternalError">
Interner Fehler: Unbekannter Zielttyp.
diff --git a/indra/newview/skins/default/xui/de/panel_preferences_general.xml b/indra/newview/skins/default/xui/de/panel_preferences_general.xml
index 201998f220..c4705d7283 100644
--- a/indra/newview/skins/default/xui/de/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/de/panel_preferences_general.xml
@@ -4,7 +4,6 @@
Sprache:
</text>
<combo_box name="language_combobox">
- <combo_box.item label="Systemvorgabe" name="System Default Language"/>
<combo_box.item label="English (Englisch)" name="English"/>
<combo_box.item label="Dansk (Dänisch) - Beta" name="Danish"/>
<combo_box.item label="Deutsch - Beta" name="Deutsch(German)"/>
diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml
index cde04d8d69..78d445f362 100644
--- a/indra/newview/skins/default/xui/de/strings.xml
+++ b/indra/newview/skins/default/xui/de/strings.xml
@@ -5740,4 +5740,25 @@ Setzen Sie den Editorpfad in Anführungszeichen
<string name="Mav_Details_MAV_UNKNOWN_VERSION">
Die Physikform hat keine korrekte Version. Legen Sie die korrekte Version für das Physikmodell fest.
</string>
+ <string name="couldnt_resolve_host">
+ Der DNS konnte den Hostnamen ([HOSTNAME]) nicht auflösen Prüfen
+Sie bitte, ob Sie die Website www.secondlife.com aufrufen können. Wenn Sie die
+Website aufrufen können, jedoch weiterhin diese Fehlermeldung erhalten,
+besuchen Sie bitte den Support-Bereich und melden Sie das Problem.
+ </string>
+ <string name="ssl_peer_certificate">
+ Der Anmeldeserver konnte sich nicht per SSL verifizieren.
+Wenn Sie diese Fehlermeldung weiterhin erhalten, besuchen
+Sie bitte den Support-Bereich der Website Secondlife.com
+und melden Sie das Problem.
+ </string>
+ <string name="ssl_connect_error">
+ Die Ursache hierfür ist häufig eine falsch eingestellte Uhrzeit auf Ihrem Computer.
+Bitte vergewissern Sie sich, dass Datum und Uhrzeit in der Systemsteuerung korrekt
+eingestellt sind. Überprüfen Sie außerdem, ob Ihre Netzwerk- und Firewall-Einstellungen
+korrekt sind. Wenn Sie diese Fehlermeldung weiterhin erhalten, besuchen Sie bitte den
+Support-Bereich der Website Secondlife.com und melden Sie das Problem.
+
+[https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 Knowledge-Base]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/en/floater_bulk_perms.xml b/indra/newview/skins/default/xui/en/floater_bulk_perms.xml
index e7ab3cacdc..9fa93b640f 100644
--- a/indra/newview/skins/default/xui/en/floater_bulk_perms.xml
+++ b/indra/newview/skins/default/xui/en/floater_bulk_perms.xml
@@ -213,6 +213,7 @@
layout="topleft"
top_pad="0"
name="share_with_group"
+ tool_tip="Allow all members of the set group to share your modify permissions for this object. You must Deed to enable role restrictions."
width="92" />
<text
type="string"
@@ -234,6 +235,7 @@
layout="topleft"
top_pad="0"
name="everyone_copy"
+ tool_tip="Anyone can take a copy of the object. Object and all of its contents must be copy and transfer permissive"
width="92" />
<text
type="string"
@@ -254,6 +256,7 @@
label="Modify"
layout="topleft"
name="next_owner_modify"
+ tool_tip="Next owner can edit properties like item name or scale of this object."
top_pad="0"
width="92" />
<check_box
@@ -263,6 +266,7 @@
layout="topleft"
top_pad="0"
name="next_owner_copy"
+ tool_tip="Next owner can make unlimited copies of this object. Copies maintain creator information, and can never be more permissive than the item being copied."
width="92">
<check_box.commit_callback
function="BulkPermission.CommitCopy"/>
@@ -276,7 +280,7 @@
label="Transfer"
layout="topleft"
name="next_owner_transfer"
- tool_tip="Next owner can give away or resell this object"
+ tool_tip="Next owner can give away or resell this object."
width="92" />
<scroll_list
enabled="false"
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index 3db431de1b..5a86eb06fb 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -73,35 +73,6 @@
prevalidate_callback="ascii"
top_pad="5"
width="290" />
- <text
- follows="left|top"
- height="15"
- layout="topleft"
- left_pad="15"
- name="model_category_label"
- text_color="White"
- top="0"
- width="200">
- This model represents...
- </text>
- <combo_box
- follows="left|top"
- height="23"
- left_pad="10"
- name="model_category_combo"
- top_pad="10"
- width="200">
- <combo_box.drop_down_button
- label_color="White"/>
- <combo_item name="Choose one" label="Choose One..." value="MUT_Unspecified"/>
- <combo_item name="Avatar shape" label="Avatar shape" value="MUT_AvatarShape"/>
- <combo_item name="Avatar attachment" label="Avatar attachment" value="MUT_AvatarAttachment"/>
- <combo_item name="Moving object (vehicle, animal)" label="Moving object (vehicle, animal)" value="MUT_MovingObject"/>
- <combo_item name="Building Component" label="Building Component" value="MUT_BuildingComponent"/>
- <combo_item name="Large, non moving etc" label="Large, non moving etc" value="MUT_LargeStationary"/>
- <combo_item name="Smaller, non-moving etc" label="Smaller, non-moving etc" value="MUT_SmallStationary"/>
- <combo_item name="Not really any of these" label="Not really any of these" value="MUT_Other"/>
- </combo_box>
</panel>
<tab_container
follows="top|left"
diff --git a/indra/newview/skins/default/xui/en/floater_my_scripts.xml b/indra/newview/skins/default/xui/en/floater_my_scripts.xml
new file mode 100644
index 0000000000..3b0b6723c7
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_my_scripts.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_resize="true"
+ height="570"
+ help_topic="scriptlimits"
+ layout="topleft"
+ name="myscripts"
+ save_rect="true"
+ title="My Scripts"
+ min_width="620"
+ width="620">
+ <panel
+ filename="panel_script_limits_my_avatar.xml"
+ follows="all"
+ bottom="555"
+ layout="topleft"
+ left="3"
+ right="-2"
+ name="script_limits_my_avatar_panel"
+ top="20"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml
index 845c1efe4d..0e62d50072 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences.xml
@@ -3,7 +3,7 @@
legacy_header_height="18"
positioning="centered"
default_tab_group="1"
- height="512"
+ height="530"
layout="topleft"
name="Preferences"
help_topic="preferences"
@@ -25,7 +25,7 @@ https://accounts.secondlife.com/change_email/
layout="topleft"
right="-105"
name="OK"
- top="473"
+ top="492"
width="90">
<button.commit_callback
function="Pref.OK" />
@@ -43,6 +43,42 @@ https://accounts.secondlife.com/change_email/
<button.commit_callback
function="Pref.Cancel" />
</button>
+
+ <panel
+ name="search_panel"
+ layout="topleft"
+ follows="left|top|right"
+ left="4"
+ right="-4"
+ top="21"
+ height="18"
+ tab_group="2">
+ <search_editor
+ clear_button_visible="true"
+ follows="left|top|right"
+ height="18"
+ label="Search Settings"
+ layout="topleft"
+ left="0"
+ max_length_bytes="255"
+ name="search_prefs_edit"
+ right="-1"
+ text_pad_left="6"
+ tool_tip="Type the search term you are interested in here. Results will be displayed for partial fulltext matches within the setting's name or comment."
+ top="0">
+ <search_editor.commit_callback
+ function="UpdateFilter" />
+ <search_editor.clear_button
+ rect.height="18"
+ rect.width="18"
+ rect.bottom="-1" />
+ <search_editor.search_button
+ rect.height="12"
+ rect.width="12"
+ rect.bottom="-1" />
+ </search_editor>
+ </panel>
+
<tab_container
follows="all"
halign="left"
@@ -54,7 +90,7 @@ https://accounts.secondlife.com/change_email/
tab_position="left"
tab_width="140"
tab_padding_right="0"
- top="21"
+ top="40"
width="658">
<panel
class="panel_preference"
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index d9a15fed9e..0abee2ff80 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -915,7 +915,8 @@
name="Object Name"
select_on_focus="true"
top_delta="0"
- width="170" />
+ width="170"
+ tool_tip="The name is limited to 63 characters. Longer prim names are cut short. Names can only consist of printable characters found in the ASCII-7 (non-extended) character set, with the exception of the vertical bar/pipe &apos;|&apos;." />
<text
follows="left|top"
height="10"
@@ -933,7 +934,8 @@
name="Object Description"
select_on_focus="true"
top_delta="0"
- width="170" />
+ width="170"
+ tool_tip="When people have &apos;Hover Tips on All Objects&apos; selected in the viewer's settings, they'll see the object description pop-up for any object under their mouse pointer. The prim description is limited to 127 bytes any string longer then that will be truncated." />
<text
type="string"
left="10"
@@ -1090,7 +1092,8 @@
layout="topleft"
name="clickaction"
width="130"
- left_pad="10">
+ left_pad="10"
+ tool_tip="A click action enables you to interact with an object with a single left click. Each click action has a special cursor indicating what it does. Some click actions have requirements to function. For example Touch and Pay require scripts" >
<combo_box.item
label="Touch (default)"
name="Touch/grab(default)"
@@ -1126,7 +1129,8 @@
layout="topleft"
name="checkbox for sale"
left="7"
- width="97" />
+ width="97"
+ tool_tip="Lets people buy this object, its content or it copy inworld for specified price." />
<!-- NEW PRICE SPINNER
Objects are allowed to be for sale for L$0 to invoke buy UI behavior
even though the user gets a free copy.
@@ -1144,7 +1148,8 @@ even though the user gets a free copy.
width="85"
min_val="0"
height="20"
- max_val="999999999" />
+ max_val="999999999"
+ tool_tip="Object cost." />
<!-- NEW SALE TYPE COMBO BOX -->
<combo_box
left_pad="8"
@@ -1157,7 +1162,8 @@ even though the user gets a free copy.
max_chars="20"
mouse_opaque="true"
name="sale type"
- width="89">
+ width="89"
+ tool_tip="Select whether purchaser will receive a copy, copy of the content or item itself." >
<combo_box.item
name="Copy"
label="Copy"
@@ -1219,6 +1225,7 @@ even though the user gets a free copy.
label="Move"
layout="topleft"
name="checkbox allow everyone move"
+ tool_tip="Anyone can move the object."
left="10"
width="85" />
<check_box
@@ -1227,6 +1234,7 @@ even though the user gets a free copy.
layout="topleft"
left_pad="0"
name="checkbox allow everyone copy"
+ tool_tip="Anyone can take a copy of the object. Object and all of its contents must be copy and transfer permissive."
width="90" />
<text
type="string"
@@ -1244,6 +1252,7 @@ even though the user gets a free copy.
left="10"
height="10"
name="checkbox next owner can modify"
+ tool_tip="Next owner can edit properties like item name or scale of this object."
width="85" />
<check_box
follows="left|top|right"
@@ -1252,6 +1261,7 @@ even though the user gets a free copy.
layout="topleft"
left_pad="0"
name="checkbox next owner can copy"
+ tool_tip="Next owner can make unlimited copies of this object. Copies maintain creator information, and can never be more permissive than the item being copied."
width="80" />
<check_box
follows="left|top|right"
@@ -1261,7 +1271,7 @@ even though the user gets a free copy.
name="checkbox next owner can transfer"
left_pad="0"
top_delta="0"
- tool_tip="Next owner can give away or resell this object"
+ tool_tip="Next owner can give away or resell this object."
width="100" />
<!-- *NOTE: These "B/O/G/E/N/F fields may overlap "perm_modify" above,
but that's OK, this is used only for debugging. -->
diff --git a/indra/newview/skins/default/xui/en/floater_top_objects.xml b/indra/newview/skins/default/xui/en/floater_top_objects.xml
index 36ceddd305..b82fe43e74 100644
--- a/indra/newview/skins/default/xui/en/floater_top_objects.xml
+++ b/indra/newview/skins/default/xui/en/floater_top_objects.xml
@@ -2,7 +2,7 @@
<floater
legacy_header_height="18"
can_resize="true"
- height="372"
+ height="350"
layout="topleft"
min_height="300"
min_width="450"
@@ -16,7 +16,7 @@
</floater.string>
<floater.string
name="top_scripts_text">
- [COUNT] scripts taking a total of [TIME] ms
+ [COUNT] scripts taking a total of [TIME] ms and using [MEMORY] KB
</floater.string>
<floater.string
name="scripts_score_label">
@@ -273,28 +273,4 @@
<button.commit_callback
function="TopObjects.ReturnAll" />
</button>
- <button
- follows="bottom|left"
- height="23"
- label="Disable Selected"
- layout="topleft"
-
- left="112"
- name="disable_selected_btn"
- width="130">
- <button.commit_callback
- function="TopObjects.DisableSelected" />
- </button>
- <button
- follows="bottom|left"
- height="23"
- label="Disable All"
- layout="topleft"
- left_pad="10"
- name="disable_all_btn"
- top_delta="0"
- width="130">
- <button.commit_callback
- function="TopObjects.DisableAll" />
- </button>
</floater>
diff --git a/indra/newview/skins/default/xui/en/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml
index 82027d9e7c..8b1d50e58f 100644
--- a/indra/newview/skins/default/xui/en/fonts.xml
+++ b/indra/newview/skins/default/xui/en/fonts.xml
@@ -9,6 +9,7 @@
<file>gulim.ttc</file>
<file>simhei.ttf</file>
<file>ArialUni.ttf</file>
+ <file>msyh.ttc</file>
</os>
<os name="Mac">
<file>ヒラギノ角ゴシック W3.ttc</file>
@@ -19,6 +20,7 @@
<file>AppleGothic.ttf</file>
<file>AppleSDGothicNeo-Regular.otf</file>
<file>åŽæ–‡ç»†é»‘.ttf</file>
+ <file>PingFang.ttc</file>
</os>
</font>
diff --git a/indra/newview/skins/default/xui/en/language_settings.xml b/indra/newview/skins/default/xui/en/language_settings.xml
index 51779e4bfd..d418fc38e3 100644
--- a/indra/newview/skins/default/xui/en/language_settings.xml
+++ b/indra/newview/skins/default/xui/en/language_settings.xml
@@ -42,6 +42,7 @@
<string name="TimeWeek">wkday,datetime,slt</string>
<string name="TimeAMPM">ampm,datetime,slt</string>
<string name="TimeHour12">hour12,datetime,slt</string>
+ <string name="TimeTimezone">timezone,datetime,slt</string>
<string name="LTimeMthNum">mthnum,datetime,local</string>
<string name="LTimeWeek">wkday,datetime,local</string>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 42744b561f..cac84cfccf 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -73,6 +73,13 @@
function="Floater.ToggleOrBringToFront"
parameter="experiences"/>
</menu_item_call>
+ <menu_item_call
+ label="My Scripts..."
+ name="MyScripts">
+ <menu_item_call.on_click
+ function="Floater.ToggleOrBringToFront"
+ parameter="my_scripts"/>
+ </menu_item_call>
<menu_item_separator/>
<menu_item_call
label="Camera Controls..."
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index cc57e1375a..d4f60078ad 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -1845,7 +1845,7 @@ You are not allowed to terraform parcel [PARCEL].
name="CannotCopyWarning"
type="alertmodal">
You do not have permission to copy the following items:
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
and will lose it from your inventory if you give it away. Do you really want to offer these items?
<tag>confirm</tag>
<usetemplate
@@ -3851,7 +3851,6 @@ Finished download of raw terrain file to:
name="RequiredUpdate"
type="alertmodal">
Version [VERSION] is required for login.
-This should have been updated for you but apparently was not.
Please download from https://secondlife.com/support/downloads/
<tag>confirm</tag>
<usetemplate
@@ -3861,6 +3860,44 @@ Please download from https://secondlife.com/support/downloads/
<notification
icon="alertmodal.tga"
+ name="PauseForUpdate"
+ type="alertmodal">
+Version [VERSION] is required for login.
+Click OK to download and install.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="OptionalUpdateReady"
+ type="alertmodal">
+Version [VERSION] has been downloaded and is ready to install.
+Click OK to install.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="PromptOptionalUpdate"
+ type="alertmodal">
+Version [VERSION] has been downloaded and is ready to install.
+Proceed?
+ <tag>confirm</tag>
+ <usetemplate
+ canceltext="Not Now"
+ name="yesnocancelbuttons"
+ notext="Skip"
+ yestext="Install"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="LoginFailedUnknown"
type="alertmodal">
Sorry, login failed for an unrecognized reason.
@@ -7766,28 +7803,6 @@ Do not allow access if you do not fully understand why it wants access to your a
</footer>
</notification>
- <notification
- icon="notify.tga"
- name="UnknownScriptQuestion"
- persist="false"
- type="notify">
-The runtime script permission requested by &apos;&lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;&apos;, an object owned by &apos;[NAME]&apos;, isn&apos;t recognized by the viewer and can&apos;t be granted.
-
-To grant this permission please update your viewer to the latest version from [DOWNLOADURL].
- <tag>confirm</tag>
- <form name="form">
- <button
- default="true"
- index="1"
- name="Deny"
- text="Ok"/>
- <button
- index="2"
- name="Mute"
- text="Block"/>
- </form>
- </notification>
-
<notification
icon="notify.tga"
name="ScriptDialog"
@@ -9479,7 +9494,7 @@ You Can't create trees and grass on land you don't own.
name="NoCopyPermsNoObject"
type="notify">
<tag>fail</tag>
-Copy failed because you lack permission to copy the object '[OBJ_NAME]'.
+Copy failed because you lack permission to copy the object &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt;.
</notification>
<notification
@@ -9487,7 +9502,7 @@ Copy failed because you lack permission to copy the object '[OBJ_NAME]'.
name="NoTransPermsNoObject"
type="notify">
<tag>fail</tag>
-Copy failed because the object '[OBJ_NAME]' cannot be transferred to you.
+Copy failed because the object &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt; cannot be transferred to you.
</notification>
<notification
@@ -9495,7 +9510,7 @@ Copy failed because the object '[OBJ_NAME]' cannot be transferred to you.
name="AddToNavMeshNoCopy"
type="notify">
<tag>fail</tag>
-Copy failed because the object '[OBJ_NAME]' contributes to navmesh.
+Copy failed because the object &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt; contributes to navmesh.
</notification>
<notification
@@ -9619,7 +9634,7 @@ Save Back To Inventory has been disabled.
name="NoExistNoSaveToContents"
type="notify">
<tag>fail</tag>
-Cannot save '[OBJ_NAME]' to object contents because the object it was rezzed from no longer exists.
+Cannot save &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt; to object contents because the object it was rezzed from no longer exists.
</notification>
<notification
@@ -9627,7 +9642,7 @@ Cannot save '[OBJ_NAME]' to object contents because the object it was rezzed fro
name="NoModNoSaveToContents"
type="notify">
<tag>fail</tag>
-Cannot save '[OBJ_NAME]' to object contents because you do not have permission to modify the object '[DEST_NAME]'.
+Cannot save &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt; to object contents because you do not have permission to modify the object &lt;nolink&gt;'[DEST_NAME]'&lt;/nolink&gt;.
</notification>
<notification
@@ -9635,7 +9650,7 @@ Cannot save '[OBJ_NAME]' to object contents because you do not have permission t
name="NoSaveBackToInvDisabled"
type="notify">
<tag>fail</tag>
-Cannot save '[OBJ_NAME]' back to inventory -- this operation has been disabled.
+Cannot save &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt; back to inventory -- this operation has been disabled.
</notification>
<notification
@@ -9643,7 +9658,7 @@ Cannot save '[OBJ_NAME]' back to inventory -- this operation has been disabled.
name="NoCopyNoSelCopy"
type="notify">
<tag>fail</tag>
-You cannot copy your selection because you do not have permission to copy the object '[OBJ_NAME]'.
+You cannot copy your selection because you do not have permission to copy the object &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt;.
</notification>
<notification
@@ -9651,7 +9666,7 @@ You cannot copy your selection because you do not have permission to copy the ob
name="NoTransNoSelCopy"
type="notify">
<tag>fail</tag>
-You cannot copy your selection because the object '[OBJ_NAME]' is not transferrable.
+You cannot copy your selection because the object &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt; is not transferrable.
</notification>
<notification
@@ -9659,7 +9674,7 @@ You cannot copy your selection because the object '[OBJ_NAME]' is not transferra
name="NoTransNoCopy"
type="notify">
<tag>fail</tag>
-You cannot copy your selection because the object '[OBJ_NAME]' is not transferrable.
+You cannot copy your selection because the object &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt; is not transferrable.
</notification>
<notification
@@ -9667,7 +9682,7 @@ You cannot copy your selection because the object '[OBJ_NAME]' is not transferra
name="NoPermsNoRemoval"
type="notify">
<tag>fail</tag>
-Removal of the object '[OBJ_NAME]' from the simulator is disallowed by the permissions system.
+Removal of the object &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt; from the simulator is disallowed by the permissions system.
</notification>
<notification
@@ -9675,7 +9690,7 @@ Removal of the object '[OBJ_NAME]' from the simulator is disallowed by the permi
name="NoModNoSaveSelection"
type="notify">
<tag>fail</tag>
-Cannot save your selection because you do not have permission to modify the object '[OBJ_NAME]'.
+Cannot save your selection because you do not have permission to modify the object &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt;.
</notification>
<notification
@@ -9683,7 +9698,7 @@ Cannot save your selection because you do not have permission to modify the obje
name="NoCopyNoSaveSelection"
type="notify">
<tag>fail</tag>
-Cannot save your selection because the object '[OBJ_NAME]' is not copyable.
+Cannot save your selection because the object &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt; is not copyable.
</notification>
<notification
@@ -9691,7 +9706,7 @@ Cannot save your selection because the object '[OBJ_NAME]' is not copyable.
name="NoModNoTaking"
type="notify">
<tag>fail</tag>
-You cannot take your selection because you do not have permission to modify the object '[OBJ_NAME]'.
+You cannot take your selection because you do not have permission to modify the object &lt;nolink&gt;'[OBJ_NAME]'&lt;/nolink&gt;.
</notification>
<notification
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_general.xml b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
index 9da044ab64..335d7caa51 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
@@ -32,11 +32,6 @@
width="200">
<combo_box.item
enabled="true"
- label="System default"
- name="System Default Language"
- value="default" />
- <combo_box.item
- enabled="true"
label="English"
name="English"
value="en" />
diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml
index 998f1ce599..52bcce01f7 100644
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -34,6 +34,46 @@
L$ [AMT]
</panel.string>
<panel
+ height="18"
+ left="-458"
+ top="0"
+ width="120"
+ follows="right|top"
+ name="menu_search_panel"
+ background_opaque="true"
+ background_visible="true"
+ bg_opaque_color="MouseGray">
+ <search_editor
+ clear_button_visible="true"
+ follows="left|top"
+ height="18"
+ label="Search Menus"
+ layout="topleft"
+ left="0"
+ max_length_bytes="255"
+ name="search_menu_edit"
+ right="-1"
+ text_pad_left="6"
+ tool_tip="Type the search term you are interested in here. Results will be displayed for partial fulltext matches within the menu."
+ top="0">
+ <search_button
+ top_pad="4"
+ left_pad="4"
+ width="12"
+ height="12"
+ image_unselected="Search"
+ image_selected="Search"/>
+ <clear_button
+ bottom="2"
+ height="12"
+ image_unselected="Icon_Close_Foreground"
+ image_selected="Icon_Close_Press"
+ pad_right="4"
+ pad_left="4"
+ width="12"/>
+ </search_editor>
+ </panel>
+ <panel
height="18"
left="-416"
width="185"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
index fd14b13ed6..acb6f5b42a 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
@@ -130,7 +130,8 @@
max_length_bytes="63"
name="LabelItemName"
top_delta="0"
- width="210" />
+ width="210"
+ tool_tip="The name is limited to 63 characters. Longer prim names are cut short. Names can only consist of printable characters found in the ASCII-7 (non-extended) character set, with the exception of the vertical bar/pipe &apos;|&apos;." />
<text
type="string"
length="1"
@@ -153,7 +154,8 @@
max_length_bytes="127"
name="LabelItemDesc"
top_delta="-5"
- width="210" />
+ width="210"
+ tool_tip="When people have &apos;Hover Tips on All Objects&apos; selected in the viewer's settings, they'll see the object description pop-up for any object under their mouse pointer. The prim description is limited to 127 bytes any string longer then that will be truncated." />
<text
type="string"
length="1"
@@ -351,6 +353,7 @@
layout="topleft"
left_pad="0"
name="CheckEveryoneCopy"
+ tool_tip="Anyone can take a copy of the object . Object and all of its contents must be copy and transfer permissive."
top_delta="-2"
width="150" />
<text
@@ -394,6 +397,7 @@
left="20"
top_pad="0"
name="CheckNextOwnerModify"
+ tool_tip="Next owner can edit properties like item name or scale of this object."
width="90" />
<check_box
height="18"
@@ -401,6 +405,7 @@
layout="topleft"
left_pad="0"
name="CheckNextOwnerCopy"
+ tool_tip="Next owner can make unlimited copies of this object. Copies maintain creator information, and can never be more permissive than the item being copied."
width="90" />
<check_box
height="18"
@@ -408,7 +413,7 @@
layout="topleft"
left_pad="0"
name="CheckNextOwnerTransfer"
- tool_tip="Next owner can give away or resell this object"
+ tool_tip="Next owner can give away or resell this object."
width="106" />
</panel>
<check_box
@@ -418,14 +423,16 @@
left="20"
name="CheckPurchase"
top_pad="20"
- width="100" />
+ width="100"
+ tool_tip="Lets people buy this object, its content or it copy inworld for specified price." />
<combo_box
height="23"
left_pad="0"
layout="topleft"
follows="left|top"
name="ComboBoxSaleType"
- width="170">
+ width="170"
+ tool_tip="Select whether purchaser will receive a copy, copy of the content or item itself." >
<combo_box.item
name="Copy"
label="Copy"
@@ -452,7 +459,8 @@
min_val="0"
height="23"
max_val="999999999"
- top_pad="10"/>
+ top_pad="10"
+ tool_tip="Object cost." />
</panel>
</scroll_container>
diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
index efedb9559e..8a3e18707f 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
@@ -130,7 +130,8 @@
max_length_bytes="63"
name="Object Name"
top_delta="0"
- width="225" />
+ width="225"
+ tool_tip="The name is limited to 63 characters. Longer prim names are cut short. Names can only consist of printable characters found in the ASCII-7 (non-extended) character set, with the exception of the vertical bar/pipe &apos;|&apos;." />
<text
type="string"
length="1"
@@ -154,7 +155,8 @@
left_delta="78"
max_length_bytes="127"
top_delta="-5"
- width="225"/>
+ width="225"
+ tool_tip="When people have &apos;Hover Tips on All Objects&apos; selected in the viewer's settings, they'll see the object description pop-up for any object under their mouse pointer. The prim description is limited to 127 bytes any string longer then that will be truncated." />
<text
type="string"
length="1"
@@ -271,23 +273,24 @@
layout="topleft"
name="clickaction"
width="168"
- left="81">
+ left="81"
+ tool_tip="A click action enables you to interact with an object with a single left click. Each click action has a special cursor indicating what it does. Some click actions have requirements to function. For example Touch and Pay require scripts" >
<combo_box.item
label="Touch (default)"
name="Touch/grab(default)"
- value="Touch" />
+ value="Touch" />
<combo_box.item
label="Sit on object"
name="Sitonobject"
- value="Sit" />
+ value="Sit" />
<combo_box.item
label="Buy object"
name="Buyobject"
- value="Buy" />
+ value="Buy" />
<combo_box.item
label="Pay object"
name="Payobject"
- value="Pay" />
+ value="Pay" />
<combo_box.item
label="Open"
name="Open"
@@ -344,6 +347,7 @@
layout="topleft"
left_pad="0"
name="checkbox allow everyone copy"
+ tool_tip="Anyone can take a copy of the object. Object and all of its contents must be copy and transfer permissive."
top_delta="-2"
width="90" />
<check_box
@@ -351,6 +355,7 @@
label="Move"
layout="topleft"
name="checkbox allow everyone move"
+ tool_tip="Anyone can move the object."
left_pad="0"
width="150" />
<text
@@ -394,6 +399,7 @@
left="20"
top_pad="0"
name="checkbox next owner can modify"
+ tool_tip="Next owner can edit properties like item name or scale of this object."
width="90" />
<check_box
height="18"
@@ -401,6 +407,7 @@
layout="topleft"
left_pad="0"
name="checkbox next owner can copy"
+ tool_tip="Next owner can make unlimited copies of this object. Copies maintain creator information, and can never be more permissive than the item being copied."
width="90" />
<check_box
height="18"
@@ -418,14 +425,16 @@
left="20"
name="checkbox for sale"
top_pad="10"
- width="100" />
+ width="100"
+ tool_tip="Lets people buy this object, its content or it copy inworld for specified price." />
<combo_box
height="23"
left_pad="0"
layout="topleft"
follows="left|top"
- name="sale type"
- width="170">
+ name="sale type"
+ width="170"
+ tool_tip="Select whether purchaser will receive a copy, copy of the content or item itself.">
<combo_box.item
name="Copy"
label="Copy"
@@ -452,7 +461,8 @@
width="150"
min_val="1"
height="20"
- max_val="999999999" />
+ max_val="999999999"
+ tool_tip="Object cost." />
<check_box
height="20"
width="110"
@@ -569,7 +579,8 @@
left="5"
name="open_btn"
top="0"
- width="73" />
+ width="73"
+ tool_tip="Open to view the Object Contents." />
<button
follows="bottom|left"
height="23"
@@ -578,7 +589,8 @@
left_pad="5"
name="pay_btn"
top="0"
- width="73" />
+ width="73"
+ tool_tip="Open Pay Window. Object must have pay script for this to work." />
<button
follows="bottom|left"
height="23"
@@ -587,7 +599,8 @@
left_pad="5"
name="buy_btn"
top="0"
- width="73" />
+ width="73"
+ tool_tip="Open Buy Window. Requires the object to be set for sale." />
<button
follows="bottom|left"
height="23"
@@ -596,7 +609,8 @@
left_pad="5"
name="details_btn"
top="0"
- width="74" />
+ width="74"
+ tool_tip="Open Inspect Object Window." />
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index f5f4b4acab..d91f3ac095 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -2675,14 +2675,14 @@ If you continue to receive this message, please contact Second Life support for
<string name="SITTING_ON">Sitting On</string>
<string name="ATTACH_CHEST">Chest</string>
- <string name="ATTACH_HEAD">Head</string>
+ <string name="ATTACH_HEAD">Skull</string>
<string name="ATTACH_LSHOULDER">Left Shoulder</string>
<string name="ATTACH_RSHOULDER">Right Shoulder</string>
<string name="ATTACH_LHAND">Left Hand</string>
<string name="ATTACH_RHAND">Right Hand</string>
<string name="ATTACH_LFOOT">Left Foot</string>
<string name="ATTACH_RFOOT">Right Foot</string>
- <string name="ATTACH_BACK">Back</string>
+ <string name="ATTACH_BACK">Spine</string>
<string name="ATTACH_PELVIS">Pelvis</string>
<string name="ATTACH_MOUTH">Mouth</string>
<string name="ATTACH_CHIN">Chin</string>
@@ -2692,16 +2692,16 @@ If you continue to receive this message, please contact Second Life support for
<string name="ATTACH_REYE">Right Eye</string>
<string name="ATTACH_NOSE">Nose</string>
<string name="ATTACH_RUARM">Right Upper Arm</string>
- <string name="ATTACH_RLARM">Right Lower Arm</string>
+ <string name="ATTACH_RLARM">Right Forearm</string>
<string name="ATTACH_LUARM">Left Upper Arm</string>
- <string name="ATTACH_LLARM">Left Lower Arm</string>
+ <string name="ATTACH_LLARM">Left Forearm</string>
<string name="ATTACH_RHIP">Right Hip</string>
<string name="ATTACH_RULEG">Right Upper Leg</string>
<string name="ATTACH_RLLEG">Right Lower Leg</string>
<string name="ATTACH_LHIP">Left Hip</string>
<string name="ATTACH_LULEG">Left Upper Leg</string>
<string name="ATTACH_LLLEG">Left Lower Leg</string>
- <string name="ATTACH_BELLY">Belly</string>
+ <string name="ATTACH_BELLY">Stomach</string>
<string name="ATTACH_LEFT_PEC">Left Pec</string>
<string name="ATTACH_RIGHT_PEC">Right Pec</string>
<string name="ATTACH_HUD_CENTER_2">HUD Center 2</string>
@@ -4233,4 +4233,29 @@ Try enclosing path to the editor with double quotes.
The physics shape does not have correct version. Set the correct version for the physics model.
</string>
+ <!-- CURL error messages -->
+ <string name="couldnt_resolve_host">
+DNS could not resolve the host name([HOSTNAME]).
+Please verify that you can connect to the www.secondlife.com
+web site. If you can, but continue to receive this error,
+please go to the support section and report this problem.
+ </string>
+ <string name="ssl_peer_certificate">
+The login server couldn't verify itself via SSL.
+If you continue to receive this error, please go
+to the Support section of the SecondLife.com web site
+and report the problem.
+ </string>
+ <string name="ssl_connect_error">
+Often this means that your computer's clock is set incorrectly.
+Please go to Control Panels and make sure the time and date
+are set correctly.
+Also check that your network and firewall are set up correctly.
+If you continue to receive this error, please go
+to the Support section of the SecondLife.com web site
+and report the problem.
+
+[https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 Knowledge Base]
+ </string>
+
</strings>
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index 70825eadbe..7b1185c4c3 100644
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -243,6 +243,10 @@ La inicialización del mercado ha fallado por un error del sistema o de la red.
Nota: Al activar esta opción, cualquiera que utilice este ordenador podrá ver tu lista de lugares favoritos.
<usetemplate name="okbutton" yestext="OK"/>
</notification>
+ <notification name="AllowMultipleViewers">
+ No es posible ejecutar varios visores Second Life ya que esta funcionalidad no es compatible. Puede provocar problemas de caché en la textura, imágenes degradadas o alteradas y un bajo rendimiento.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="GrantModifyRights">
Al conceder permisos de modificación a otro Residente, le estás permitiendo cambiar, borrar o tomar CUALQUIER objeto que tengas en el mundo. Sé MUY cuidadoso al conceder este permiso.
¿Quieres conceder permisos de modificación a [NAME]?
@@ -713,8 +717,9 @@ La calidad gráfica puede ajustarse en Preferencias &gt; Gráficos.
No tienes permiso para modificar el terreno de la parcela [PARCEL].
</notification>
<notification name="CannotCopyWarning">
- No tienes permiso para copiar los elementos siguientes:
-[ITEMS] y, si los das, los perderás del inventario. ¿Seguro que quieres ofrecerlos?
+ No tienes permiso para copiar los elementos siguientes:
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
+y, si los das, los perderás del inventario. ¿Seguro que quieres ofrecerlos?
<usetemplate name="okcancelbuttons" notext="No" yestext="Sí"/>
</notification>
<notification name="CannotGiveItem">
@@ -3712,13 +3717,13 @@ no está en la misma región que tú.
No puedes crear árboles y hierba en un terreno que no es tuyo.
</notification>
<notification name="NoCopyPermsNoObject">
- Error al copiar: careces de permiso para copiar el objeto &apos;[OBJ_NAME]&apos;.
+ Error al copiar porque no tienes permiso para copiar el objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoTransPermsNoObject">
- Error al copiar: no se te puede transferir el objeto &apos;[OBJ_NAME]&apos;.
+ Error al copiar porque no puedes recibir una transferencia del objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="AddToNavMeshNoCopy">
- Error al copiar porque el objeto &apos;[OBJ_NAME]&apos; contribuye al navmesh.
+ Error al copiar porque el objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; contribuye a navmesh.
</notification>
<notification name="DupeWithNoRootsSelected">
Duplicación sin objetos raíz seleccionados.
@@ -3763,34 +3768,34 @@ Prueba otra vez dentro de un minuto.
Se ha deshabilitado Devolver el objeto a mi inventario.
</notification>
<notification name="NoExistNoSaveToContents">
- No se puede guardar &apos;[OBJ_NAME]&apos; en el contenido del objeto porque el objeto desde el cual ha sido colocado ya no existe.
+ No se puede guardar &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; en los contenidos del objeto porque el objeto a partir del cual fue creado ya no existe.
</notification>
<notification name="NoModNoSaveToContents">
- No se puede guardar &apos;[OBJ_NAME]&apos; en el contenido del objeto porque no tienes permiso para modificar el objeto &apos;[DEST_NAME]&apos;.
+ No se puede guardar &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; en los contenidos del objeto porque no tienes permiso para modificar el objeto &lt;nolink&gt;&apos;[DEST_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoSaveBackToInvDisabled">
- No se puede guardar &apos;[OBJ_NAME]&apos; de nuevo en el inventario; esta operación está desactivada.
+ No se puede volver a guardar &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; en el inventario. Esta operación fue desactivada.
</notification>
<notification name="NoCopyNoSelCopy">
- No se puede copiar tu selección porque no tienes permiso para copiar el objeto &apos;[OBJ_NAME]&apos;.
+ No puedes copiar el elemento seleccionado porque no tienes permiso para copiar el objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoTransNoSelCopy">
- No se puede copiar tu selección porque el objeto &apos;[OBJ_NAME]&apos; es intransferible.
+ No puedes copiar el elemento seleccionado porque el objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; no es transferible.
</notification>
<notification name="NoTransNoCopy">
- No se puede copiar tu selección porque el objeto &apos;[OBJ_NAME]&apos; es intransferible.
+ No puedes copiar el elemento seleccionado porque el objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; no es transferible.
</notification>
<notification name="NoPermsNoRemoval">
- El sistema de permisos no admite la eliminación del objeto &apos;[OBJ_NAME]&apos; del simulador.
+ El sistema de permisos no autoriza quitar el objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; del simulador.
</notification>
<notification name="NoModNoSaveSelection">
- No se puede guardar tu selección porque no tienes permiso para modificar el objeto &apos;[OBJ_NAME]&apos;.
+ No puedes guardar el elemento seleccionado porque no tienes permiso para modificar el objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoCopyNoSaveSelection">
- No se puede guardar tu selección porque el objeto &apos;[OBJ_NAME]&apos; no se puede copiar.
+ No puedes guardar el elemento seleccionado porque el objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; no puede ser copiado.
</notification>
<notification name="NoModNoTaking">
- No se puede aceptar tu selección porque no tienes permiso para modificar el objeto &apos;[OBJ_NAME]&apos;.
+ No puedes tomar el elemento seleccionado porque no tienes permiso para modificar el objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="RezDestInternalError">
Error interno: tipo de destino desconocido.
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_general.xml b/indra/newview/skins/default/xui/es/panel_preferences_general.xml
index 7d3c33a781..d2246630d8 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_general.xml
@@ -4,7 +4,6 @@
Idioma:
</text>
<combo_box name="language_combobox">
- <combo_box.item label="Predeterminado del sistema" name="System Default Language"/>
<combo_box.item label="English (Inglés)" name="English"/>
<combo_box.item label="Dansk (danés) - Beta" name="Danish"/>
<combo_box.item label="Deutsch (Alemán) - Beta" name="Deutsch(German)"/>
diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml
index 36a2711a5c..15e3c0622d 100644
--- a/indra/newview/skins/default/xui/es/strings.xml
+++ b/indra/newview/skins/default/xui/es/strings.xml
@@ -5651,4 +5651,25 @@ Inténtalo incluyendo la ruta de acceso al editor entre comillas
<string name="Mav_Details_MAV_UNKNOWN_VERSION">
La versión de la forma física no es correcta. Configura la versión correcta del modelo físico.
</string>
+ <string name="couldnt_resolve_host">
+ Error de DNS al resolver el nombre del host([HOSTNAME]).
+Por favor verifica si puedes conectarte al sitio web www.secondlife.com.
+Si puedes conectarte, pero aún recibes este error, por favor accede a
+la sección Soporte y genera un informe del problema.
+ </string>
+ <string name="ssl_peer_certificate">
+ El servidor de inicio de sesión no pudo verificarse vía SSL.
+Si aún recibes este error, por favor accede a
+la sección Soporte del sitio web Secondlife.com
+y genera un informe del problema.
+ </string>
+ <string name="ssl_connect_error">
+ En general esto significa que el horario de tu computadora no está bien configurado.
+Por favor accede al Panel de control y asegúrate de que la hora y la fecha estén
+bien configurados. Verifica también que tu red y tu cortafuegos estén bien
+configurados. Si aún recibes este error, por favor accede a la sección Soporte
+del sitio web Secondlife.com y genera un informe del problema.
+
+[https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 Base de conocimientos]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml
index 74abecf760..9066f1e70c 100644
--- a/indra/newview/skins/default/xui/fr/notifications.xml
+++ b/indra/newview/skins/default/xui/fr/notifications.xml
@@ -244,6 +244,10 @@ Veuillez ne sélectionner qu&apos;un seul objet.
Remarque : si vous activez cette option, toutes les personnes utilisant cet ordinateur pourront voir votre liste d&apos;endroits favoris.
<usetemplate name="okbutton" yestext="OK"/>
</notification>
+ <notification name="AllowMultipleViewers">
+ L&apos;exécution de plusieurs visualiseurs Second Life n&apos;est pas prise en charge. Cela peut entraîner des collisions de cache de texture, une corruption et une dégradation des visuels et des performances.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="GrantModifyRights">
Lorsque vous accordez des droits de modification à un autre résident, vous lui permettez de changer, supprimer ou prendre n&apos;importe lequel de vos objets dans Second Life. Réfléchissez bien avant d&apos;accorder ces droits.
Voulez-vous vraiment accorder des droits de modification à [NAME] ?
@@ -717,9 +721,9 @@ La qualité des graphiques peut être augmentée à la section Préférences &gt
Vous n&apos;êtes pas autorisé(e) à terraformer la parcelle [PARCEL].
</notification>
<notification name="CannotCopyWarning">
- Vous n&apos;êtes pas autorisé à copier les articles suivants :
-[ITEMS].
-Ceux-ci disparaîtront donc de votre inventaire si vous les donnez. Voulez-vous vraiment offrir ces articles ?
+ Vous n&apos;êtes pas autorisé à copier les objets suivants :
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
+et il disparaîtra de votre inventaire si vous le donnez. Voulez-vous vraiment offrir ces articles ?
<usetemplate name="okcancelbuttons" notext="Non" yestext="Oui"/>
</notification>
<notification name="CannotGiveItem">
@@ -3715,13 +3719,13 @@ il ne se trouve pas dans la même région que vous.
Vous ne pouvez pas créer d&apos;arbres ni d&apos;herbe sur un terrain qui ne vous appartient pas.
</notification>
<notification name="NoCopyPermsNoObject">
- Échec de la copie car vous ne disposez pas des droits requis pour copier l&apos;objet [OBJ_NAME].
+ La copie a échoué car vous ne disposez pas de l&apos;autorisation nécessaire pour copier l&apos;objet &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoTransPermsNoObject">
- Échec de la copie car l&apos;objet [OBJ_NAME] ne peut pas vous être transféré.
+ La copie a échoué car l&apos;objet &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; ne peut pas vous être transféré.
</notification>
<notification name="AddToNavMeshNoCopy">
- Échec de la copie car l&apos;objet [OBJ_NAME] contribue au maillage de navigation.
+ La copie a échoué car l&apos;objet &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; contribue à navmesh.
</notification>
<notification name="DupeWithNoRootsSelected">
Dupliquer sans objet racine sélectionné
@@ -3766,34 +3770,34 @@ Veuillez réessayer dans une minute.
Le réenregistrement dans l&apos;inventaire a été désactivé.
</notification>
<notification name="NoExistNoSaveToContents">
- Impossible d&apos;enregistrer [OBJ_NAME] dans le contenu des objets car l&apos;objet à partir duquel il a été rezzé n&apos;existe plus.
+ Impossible de sauvegarder &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; dans le contenu de l&apos;objet car l&apos;objet à partir duquel il a été rezzé n&apos;existe plus.
</notification>
<notification name="NoModNoSaveToContents">
- Impossible d&apos;enregistrer [OBJ_NAME] dans le contenu des objets car vous ne disposez pas des droits requis pour modifier l&apos;objet [DEST_NAME].
+ Impossible de sauvegarder&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; dans le contenu de l&apos;objet car vous n&apos;êtes pas autorisé à modifier l&apos;objet &lt;nolink&gt;&apos;[DEST_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoSaveBackToInvDisabled">
- Impossible de réenregistrer [OBJ_NAME] dans l&apos;inventaire -- cette opération a été désactivée.
+ Impossible de sauvegarder &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; dans l&apos;inventaire - cette opération a été désactivée.
</notification>
<notification name="NoCopyNoSelCopy">
- Vous ne pouvez pas copier votre sélection car vous n&apos;avez pas le droit de copier l&apos;objet [OBJ_NAME].
+ Vous ne pouvez pas copier votre sélection parce que vous n&apos;êtes pas autorisé à copier l&apos;objet &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoTransNoSelCopy">
- Vous ne pouvez pas copier votre sélection car l&apos;objet [OBJ_NAME] n&apos;est pas transférable.
+ Vous ne pouvez pas copier votre sélection parce que l&apos;objet &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; n&apos;est pas transférable.
</notification>
<notification name="NoTransNoCopy">
- Vous ne pouvez pas copier votre sélection car l&apos;objet [OBJ_NAME] n&apos;est pas transférable.
+ Vous ne pouvez pas copier votre sélection parce que l&apos;objet &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; n&apos;est pas transférable.
</notification>
<notification name="NoPermsNoRemoval">
- La suppression de l&apos;objet [OBJ_NAME] du simulateur n&apos;est pas autorisée par le système de droits.
+ La suppression de l&apos;objet &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; du simulateur n&apos;est pas autorisée par le système d&apos;autorisations.
</notification>
<notification name="NoModNoSaveSelection">
- Vous ne pouvez pas enregistrer votre sélection car vous n&apos;avez pas le droit de modifier l&apos;objet [OBJ_NAME].
+ Impossible de sauvegarder votre sélection parce que vous n&apos;êtes pas autorisé à modifier l&apos;objet &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoCopyNoSaveSelection">
- Vous ne pouvez pas enregistrer votre sélection car l&apos;objet [OBJ_NAME] ne peut pas être copié.
+ Impossible d&apos;enregistrer votre sélection car l&apos;objet &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; n&apos;est pas copiable.
</notification>
<notification name="NoModNoTaking">
- Vous ne pouvez pas prendre votre sélection car vous n&apos;avez pas le droit de modifier l&apos;objet [OBJ_NAME].
+ Vous ne pouvez pas sauvegarder votre sélection parce que vous n&apos;êtes pas autorisé à modifier l&apos;objet &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="RezDestInternalError">
Erreur interne : type de destination inconnue.
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_general.xml b/indra/newview/skins/default/xui/fr/panel_preferences_general.xml
index 11b1bd9b87..b75567a40f 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_general.xml
@@ -4,7 +4,6 @@
Langue :
</text>
<combo_box name="language_combobox">
- <combo_box.item label="Choix par défaut" name="System Default Language"/>
<combo_box.item label="English (Anglais)" name="English"/>
<combo_box.item label="Dansk (Danois) - Bêta" name="Danish"/>
<combo_box.item label="Deutsch (Allemand) - Bêta" name="Deutsch(German)"/>
diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml
index 7f5851b51d..13dd2b3640 100644
--- a/indra/newview/skins/default/xui/fr/strings.xml
+++ b/indra/newview/skins/default/xui/fr/strings.xml
@@ -5741,4 +5741,25 @@ Essayez avec le chemin d&apos;accès à l&apos;éditeur entre guillemets doubles
<string name="Mav_Details_MAV_UNKNOWN_VERSION">
La forme physique n’a pas la version correcte. Configurez la version correcte pour le modèle physique.
</string>
+ <string name="couldnt_resolve_host">
+ DNS n&apos;a pas pu résoudre le nom d&apos;hôte([HOSTNAME]).
+Veuillez vérifier que vous parvenez à vous connecter au site www.secondlife.com.
+Si c&apos;est le cas, et que vous continuez à recevoir ce message d&apos;erreur, veuillez vous
+rendre à la section Support et signaler ce problème
+ </string>
+ <string name="ssl_peer_certificate">
+ Le serveur d&apos;identification a rencontré une erreur de connexion SSL.
+Si vous continuez à recevoir ce message d&apos;erreur,
+veuillez vous rendre à la section Support du site web
+SecondLife.com et signaler ce problème
+ </string>
+ <string name="ssl_connect_error">
+ Ceci est souvent dû à un mauvais réglage de l&apos;horloge de votre ordinateur.
+Veuillez aller à Tableaux de bord et assurez-vous que l&apos;heure et la date sont réglés
+correctement. Vérifiez également que votre réseau et votre pare-feu sont configurés
+correctement. Si vous continuez à recevoir ce message d&apos;erreur, veuillez vous rendre
+à la section Support du site web SecondLife.com et signaler ce problème.
+
+[https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 Base de connaissances]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml
index d1a47535d8..8a057914ac 100644
--- a/indra/newview/skins/default/xui/it/notifications.xml
+++ b/indra/newview/skins/default/xui/it/notifications.xml
@@ -244,6 +244,10 @@ Scegli solo un oggetto e riprova.
Nota: Se attivi questa opzione, chiunque usa questo computer può vedere l&apos;elenco di luoghi preferiti.
<usetemplate name="okbutton" yestext="OK"/>
</notification>
+ <notification name="AllowMultipleViewers">
+ Non è possibile utilizzare più di un viewer Second Life contemporaneamente. L’utilizzo simultaneo potrebbe portare a collisioni o corruzione della cache texture, e ad un peggioramento nelle immagini e nella performance.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="GrantModifyRights">
Quando concedi i diritti di modifica ad un altro residente, gli permetti di modificare, eliminare o prendere QUALSIASI oggetto che possiedi in Second Life. Pertanto ti consigliamo di essere ben sicuro quando concedi questo diritto.
Vuoi concedere i diritti di modifica a [NAME]?
@@ -716,8 +720,8 @@ La qualità grafica può essere aumentata in Preferenze &gt; Grafica.
</notification>
<notification name="CannotCopyWarning">
Non hai l&apos;autorizzazione a copiare i seguenti oggetti:
-[ITEMS]
-e se li dai via, verranno eliminati dal tuo inventario. Sicuro di volere offrire questi oggetti?
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
+e se li dai via, verranno eliminati dal tuo inventario. Sicuro di voler offrire questi oggetti?
<usetemplate name="okcancelbuttons" notext="No" yestext="Si"/>
</notification>
<notification name="CannotGiveItem">
@@ -3719,13 +3723,13 @@ non è nella stessa regione in cui ti trovi.
Non puoi creare alberi ed erba su terreni che non sono di tua proprietà.
</notification>
<notification name="NoCopyPermsNoObject">
- Copia non riuscita perché non hai l&apos;autorizzazione necessaria per copiare l&apos;oggetto &apos;[OBJ_NAME]&apos;.
+ Copia non riuscita perché non hai il permesso per copiare l’oggetto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoTransPermsNoObject">
- La copia non è riuscita perché &apos;[OBJ_NAME]&apos; non può essere trasferito a te.
+ Copia non riuscita perché l’oggetto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; non può esserti trasferito.
</notification>
<notification name="AddToNavMeshNoCopy">
- La copia non è riuscita perché &apos;[OBJ_NAME]&apos; contribuisce al navmesh.
+ Copia non riuscita perché l’oggetto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; contribuisce al navmesh.
</notification>
<notification name="DupeWithNoRootsSelected">
Duplicato senza oggetto principale selezionato.
@@ -3770,34 +3774,34 @@ Riprova tra un minuto.
Opzione Salva nell&apos;inventario disattivata
</notification>
<notification name="NoExistNoSaveToContents">
- Impossibile salvare &apos;[OBJ_NAME]&apos; nei contenuti dell&apos;oggetto perché l&apos;oggetto da cui è stato razzato non esiste più.
+ Impossibile salvare &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; in contenuti oggetto perché l’oggetto da cui è stato rezzato non esiste più.
</notification>
<notification name="NoModNoSaveToContents">
- Impossibile salvare &apos;[OBJ_NAME]&apos; nei contenuti dell&apos;oggetto perché non hai l&apos;autorizzazione necessaria per modificare l&apos;oggetto &apos;[DEST_NAME]&apos;.
+ Impossibile salvare &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; in contenuti oggetto perché non hai i permessi per modificare l’oggetto &lt;nolink&gt;&apos;[DEST_NAME]’&lt;/nolink&gt;.
</notification>
<notification name="NoSaveBackToInvDisabled">
- Impossibile riportare &apos;[OBJ_NAME]&apos; nell&apos;inventario -- questa operazione è stata disattivata.
+ Impossibile salvare &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nell’inventario: questa operazione è stata disabilitata.
</notification>
<notification name="NoCopyNoSelCopy">
- Non puoi copiare l&apos;elemento selezionato perché non hai l&apos;autorizzazione necessaria per copiare l&apos;oggetto &apos;[OBJ_NAME]&apos;.
+ Non puoi copiare la selezione perché non hai il permesso di copiare l’oggetto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoTransNoSelCopy">
- Non puoi copiare la selezione perché l&apos;oggetto &apos;[OBJ_NAME]&apos; non può essere trasferito.
+ Non puoi copiare la selezione perché l’oggetto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; non è trasferibile.
</notification>
<notification name="NoTransNoCopy">
- Non puoi copiare la selezione perché l&apos;oggetto &apos;[OBJ_NAME]&apos; non può essere trasferito.
+ Non puoi copiare la selezione perché l’oggetto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; non è trasferibile.
</notification>
<notification name="NoPermsNoRemoval">
- La rimozione dell&apos;oggetto &apos;[OBJ_NAME]&apos; dal simulatore non è consentita dal sistema delle autorizzazioni.
+ La rimozione dell’oggetto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; dal simulatore è disattivata dal sistema dei permessi.
</notification>
<notification name="NoModNoSaveSelection">
- Non puoi salvare l&apos;elemento selezionato perché non hai l&apos;autorizzazione necessaria per modificare l&apos;oggetto &apos;[OBJ_NAME]&apos;.
+ Non puoi copiare la selezione perché non hai il permesso di modificare l’oggetto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoCopyNoSaveSelection">
- Non puoi salvare la selezione perché l&apos;oggetto &apos;[OBJ_NAME]&apos; non può essere copiato.
+ Non puoi copiare la selezione perché l’oggetto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; non è copiabile.
</notification>
<notification name="NoModNoTaking">
- Non puoi prendere l&apos;elemento selezionato perché non hai l&apos;autorizzazione necessaria per modificare l&apos;oggetto &apos;[OBJ_NAME]&apos;.
+ Non puoi prendere ciò che hai selezionato perché non hai il permesso di modificare l’oggetto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="RezDestInternalError">
Errore interno: Tipo di destinazione sconosciuto.
diff --git a/indra/newview/skins/default/xui/it/panel_preferences_general.xml b/indra/newview/skins/default/xui/it/panel_preferences_general.xml
index ef999d03c0..49edc0aa12 100644
--- a/indra/newview/skins/default/xui/it/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/it/panel_preferences_general.xml
@@ -4,7 +4,6 @@
Lingua:
</text>
<combo_box name="language_combobox">
- <combo_box.item label="Default di sistema" name="System Default Language"/>
<combo_box.item label="English" name="English"/>
<combo_box.item label="Dansk (Danese) - Beta" name="Danish"/>
<combo_box.item label="Deutsch (Tedesco) - Beta" name="Deutsch(German)"/>
diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml
index 918e655ab6..be3acc14b3 100644
--- a/indra/newview/skins/default/xui/it/strings.xml
+++ b/indra/newview/skins/default/xui/it/strings.xml
@@ -5656,4 +5656,25 @@ Prova a racchiudere il percorso dell&apos;editor in doppie virgolette.
<string name="Mav_Details_MAV_UNKNOWN_VERSION">
La versione della forma fisica non è corretta. Imposta la versione corretta per il modello della fisica.
</string>
+ <string name="couldnt_resolve_host">
+ Il DNS non ha potuto risolvere il nome dell’host([HOSTNAME]).
+Verifica di riuscire a connetterti al sito web www.secondlife.com.
+Se riesci ma continui a ricevere questo errore, visita la sezione
+Assistenza e segnala il problema.
+ </string>
+ <string name="ssl_peer_certificate">
+ Il server per il login non ha potuto effettuare la verifica tramite SSL.
+Se continui a ricevere questo errore, visita
+la sezione Assistenza nel sito SecondLife.com
+e segnala il problema.
+ </string>
+ <string name="ssl_connect_error">
+ Spesso l’errore è dovuto all’orologio del computer, impostato incorrettamente.
+Vai al Pannello di Controllo e assicurati che data e ora siano
+esatte. Controlla anche che il network e il firewall siano impostati
+correttamente. Se continui a ricevere questo errore, visita la sezione
+Assistenza nel sito SecondLife.com e segnala il problema.
+
+[https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 Base conoscenze]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml
index 99ba5b2655..fc6c951a55 100644
--- a/indra/newview/skins/default/xui/ja/notifications.xml
+++ b/indra/newview/skins/default/xui/ja/notifications.xml
@@ -244,6 +244,10 @@
注æ„:ã“ã®ã‚ªãƒ—ションを有効ã«ã™ã‚‹ã¨ã€ã“ã®ãƒ‘ソコンを使ã†ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯èª°ã§ã‚‚ã€ã‚ãªãŸã®ãŠæ°—ã«å…¥ã‚Šã®å ´æ‰€ã‚’見るã“ã¨ãŒã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚
<usetemplate name="okbutton" yestext="OK"/>
</notification>
+ <notification name="AllowMultipleViewers">
+ 複数㮠Second Life ビューワを実行ã™ã‚‹ã“ã¨ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。テクスãƒãƒ£ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã®ã‚³ãƒªã‚¸ãƒ§ãƒ³ã‚„ç ´æã€ãŠã‚ˆã³ãƒ“ジュアルã¨ãƒ‘フォーマンスã®ä½Žä¸‹ã«ã¤ãªãŒã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="GrantModifyRights">
他人ã«ä¿®æ­£æ¨©é™ã‚’与ãˆã‚‹ã¨ã€æ¨©é™ã‚’与ãˆã‚‰ã‚ŒãŸäººã¯ã‚ãªãŸãŒæ‰€æœ‰ã™ã‚‹ã‚¤ãƒ³ãƒ¯ãƒ¼ãƒ«ãƒ‰ã®ã‚ªãƒ–ジェクトを変更ã€å‰Šé™¤ã€æŒã¡å¸°ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ã“ã®æ¨©é™ã‚’与ãˆã‚‹éš›ã«ã¯å分ã«æ³¨æ„ã—ã¦ãã ã•ã„。
[NAME] ã«ä¿®æ­£æ¨©é™ã‚’与ãˆã¾ã™ã‹ï¼Ÿ
@@ -735,7 +739,9 @@ L$ ãŒä¸è¶³ã—ã¦ã„ã‚‹ã®ã§ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«å‚加ã™ã‚‹ã“ã¨ãŒã§ãã
ã‚ãªãŸã«ã¯ [PARCEL] 区画を地形編集ã™ã‚‹è¨±å¯ãŒã‚ã‚Šã¾ã›ã‚“。
</notification>
<notification name="CannotCopyWarning">
- ã‚ãªãŸã«ã¯[ITEMS]ã¨ã„ã†ã‚¢ã‚¤ãƒ†ãƒ ã‚’コピーã™ã‚‹è¨±å¯ãŒã‚ã‚Šã¾ã›ã‚“。他ã®ä½äººã«æä¾›ã™ã‚‹ã¨ã€ãã®ã‚¢ã‚¤ãƒ†ãƒ ã¯ã‚ãªãŸã®ã‚¤ãƒ³ãƒ™ãƒ³ãƒˆãƒªã‹ã‚‰å‰Šé™¤ã•ã‚Œã¾ã™ã€‚本当ã«ã“れらã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’譲りã¾ã™ã‹ï¼Ÿ
+ ã‚ãªãŸã«ã¯æ¬¡ã‚¢ã‚¤ãƒ†ãƒ ã‚’コピーã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“:
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
+ä»–ã®ä½äººã«è­²ã‚‹ã¨ã€ãã®ã‚¢ã‚¤ãƒ†ãƒ ã¯ã‚ãªãŸã®æŒã¡ç‰©ã‹ã‚‰å‰Šé™¤ã•ã‚Œã¾ã™ã€‚本当ã«ã“れらã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’譲りã¾ã™ã‹ï¼Ÿ
<usetemplate name="okcancelbuttons" notext="ã„ã„ãˆ" yestext="ã¯ã„"/>
</notification>
<notification name="CannotGiveItem">
@@ -3756,13 +3762,13 @@ M キーを押ã—ã¦å¤‰æ›´ã—ã¾ã™ã€‚
所有ã—ã¦ã„ãªã„土地ã«æœ¨ã‚„è‰ã‚’æ¤ãˆã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。
</notification>
<notification name="NoCopyPermsNoObject">
- オブジェクト &apos;[OBJ_NAME]&apos; をコピーã™ã‚‹æ¨©é™ãŒãªã„ãŸã‚ã€ã‚³ãƒ”ーã«å¤±æ•—ã—ã¾ã—ãŸã€‚
+ ã‚ãªãŸã«ã¯ã‚ªãƒ–ジェクト &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; をコピーã™ã‚‹æ¨©é™ãŒãªã„ãŸã‚ã€ã‚³ãƒ”ーã«å¤±æ•—ã—ã¾ã—ãŸã€‚
</notification>
<notification name="NoTransPermsNoObject">
- オブジェクト &apos;[OBJ_NAME]&apos; ã‚’ã‚ãªãŸã«è»¢é€ã§ããªã„ãŸã‚ã€ã‚³ãƒ”ーã«å¤±æ•—ã—ã¾ã—ãŸã€‚
+ オブジェクト &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; ã¯ã‚ãªãŸã«è­²æ¸¡ã§ããªã„ãŸã‚ã€ã‚³ãƒ”ーã«å¤±æ•—ã—ã¾ã—ãŸã€‚
</notification>
<notification name="AddToNavMeshNoCopy">
- オブジェクト &apos;[OBJ_NAME]&apos; ãŒãƒŠãƒ“メッシュã«è²¢çŒ®ã—ã¦ã„ã‚‹ãŸã‚ã€ã‚³ãƒ”ーã«å¤±æ•—ã—ã¾ã—ãŸã€‚
+ オブジェクト &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; 㯠navmesh ã«é–¢é€£ãŒã‚ã‚‹ãŸã‚ã€ã‚³ãƒ”ーã«å¤±æ•—ã—ã¾ã—ãŸã€‚
</notification>
<notification name="DupeWithNoRootsSelected">
ルートオブジェクトをé¸æŠžã›ãšã«è¤‡è£½ã—ã¾ã™ã€‚
@@ -3807,34 +3813,34 @@ M キーを押ã—ã¦å¤‰æ›´ã—ã¾ã™ã€‚
「「æŒã¡ç‰©ã€ã«ä¿å­˜ã€ãŒç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚
</notification>
<notification name="NoExistNoSaveToContents">
- &apos;[OBJ_NAME]&apos; ã® Rez å…ƒã§ã‚るオブジェクトãŒå­˜åœ¨ã—ãªã„ãŸã‚ã€ã“ã®ã‚ªãƒ–ジェクトをオブジェクトコンテンツã«ä¿å­˜ã§ãã¾ã›ã‚“。
+ 「存在ã—ã¾ã›ã‚“ã€ã‹ã‚‰ rez ã•ã‚ŒãŸãŸã‚ã€&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; をオブジェクトã®ä¸­èº«ã«ä¿å­˜ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚
</notification>
<notification name="NoModNoSaveToContents">
- オブジェクト &apos;[DEST_NAME]&apos; を修正ã™ã‚‹æ¨©é™ãŒãªã„ãŸã‚ã€ã‚ªãƒ–ジェクトã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã« &apos;[OBJ_NAME]&apos; ã‚’ä¿å­˜ã§ãã¾ã›ã‚“。
+ ã‚ãªãŸã«ã¯ã‚ªãƒ–ジェクト &lt;nolink&gt;&apos;[DEST_NAME]&apos;&lt;/nolink&gt; を修正ã™ã‚‹æ¨©é™ãŒãªã„ãŸã‚ã€&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;をオブジェクトã®ä¸­èº«ã«ä¿å­˜ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚
</notification>
<notification name="NoSaveBackToInvDisabled">
- インベントリ㫠&apos;[OBJ_NAME]&apos; ã‚’ä¿å­˜ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“ - ã“ã®æ“作ãŒç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; をインベントリã«ä¿å­˜ã§ãã¾ã›ã‚“。ã“ã®æ“作ã¯ç„¡åŠ¹ã«ãªã‚Šã¾ã—ãŸã€‚
</notification>
<notification name="NoCopyNoSelCopy">
- オブジェクト &apos;[OBJ_NAME]&apos; を変更ã™ã‚‹æ¨©é™ã‚’æŒã£ã¦ã„ãªã„ãŸã‚ã€é¸æŠžã—ãŸã‚‚ã®ã‚’コピーã§ãã¾ã›ã‚“。
+ ã‚ãªãŸã«ã¯ã‚ªãƒ–ジェクト &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; をコピーã™ã‚‹æ¨©é™ãŒãªã„ãŸã‚ã€é¸æŠžå†…容をコピーã§ãã¾ã›ã‚“。
</notification>
<notification name="NoTransNoSelCopy">
- オブジェクト &apos;[OBJ_NAME]&apos; を転é€ã§ããªã„ãŸã‚ã€é¸æŠžã—ãŸã‚‚ã®ã‚’コピーã§ãã¾ã›ã‚“。
+ オブジェクト &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; を譲渡ã§ããªã„ãŸã‚ã€é¸æŠžå†…容をコピーã§ãã¾ã›ã‚“。
</notification>
<notification name="NoTransNoCopy">
- オブジェクト &apos;[OBJ_NAME]&apos; を転é€ã§ããªã„ãŸã‚ã€é¸æŠžã—ãŸã‚‚ã®ã‚’コピーã§ãã¾ã›ã‚“。
+ オブジェクト &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; を譲渡ã§ããªã„ãŸã‚ã€é¸æŠžå†…容をコピーã§ãã¾ã›ã‚“。
</notification>
<notification name="NoPermsNoRemoval">
- シミュレータã‹ã‚‰ã®ã‚ªãƒ–ジェクト &apos;[OBJ_NAME]&apos; ã®å‰Šé™¤ã¯ã€æ¨©é™ã‚·ã‚¹ãƒ†ãƒ ã«ã‚ˆã£ã¦ç„¡åŠ¹ã«ã•ã‚Œã¦ã„ã¾ã™ã€‚
+ オブジェクト &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; をシミュレーターã‹ã‚‰å‰Šé™¤ã™ã‚‹ã“ã¨ã¯ã€æ¨©é™ã®ã‚·ã‚¹ãƒ†ãƒ ã«ã‚ˆã‚Šè¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“。
</notification>
<notification name="NoModNoSaveSelection">
- オブジェクト &apos;[OBJ_NAME]&apos; を変更ã™ã‚‹æ¨©é™ã‚’æŒã£ã¦ã„ãªã„ãŸã‚ã€é¸æŠžã—ãŸã‚‚ã®ã‚’ä¿å­˜ã§ãã¾ã›ã‚“。
+ ã‚ãªãŸã«ã¯ã‚ªãƒ–ジェクト &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; を修正ã™ã‚‹æ¨©é™ãŒãªã„ãŸã‚ã€é¸æŠžå†…容をä¿å­˜ã§ãã¾ã›ã‚“。
</notification>
<notification name="NoCopyNoSaveSelection">
- オブジェクト &apos;[OBJ_NAME]&apos; をコピーã§ããªã„ãŸã‚ã€é¸æŠžã—ãŸã‚‚ã®ã‚’ä¿å­˜ã§ãã¾ã›ã‚“。
+ オブジェクト &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; ã¯ã‚³ãƒ”ーä¸å¯ãªãŸã‚ã€é¸æŠžå†…容をä¿å­˜ã§ãã¾ã›ã‚“。
</notification>
<notification name="NoModNoTaking">
- オブジェクト &apos;[OBJ_NAME]&apos; を変更ã™ã‚‹æ¨©é™ã‚’æŒã£ã¦ã„ãªã„ãŸã‚ã€é¸æŠžã—ãŸã‚‚ã®ã‚’å–å¾—ã§ãã¾ã›ã‚“。
+ ã‚ãªãŸã«ã¯ã‚ªãƒ–ジェクト &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; を修正ã™ã‚‹æ¨©é™ãŒãªã„ãŸã‚ã€é¸æŠžå†…容をé¸ã¶ã“ã¨ã¯ã§ãã¾ã›ã‚“。
</notification>
<notification name="RezDestInternalError">
内部エラー: ä¸æ˜Žãªå®›å…ˆã‚¿ã‚¤ãƒ—。
diff --git a/indra/newview/skins/default/xui/ja/panel_preferences_general.xml b/indra/newview/skins/default/xui/ja/panel_preferences_general.xml
index e2b74354fa..378cf8652e 100644
--- a/indra/newview/skins/default/xui/ja/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/ja/panel_preferences_general.xml
@@ -4,7 +4,6 @@
言語:
</text>
<combo_box name="language_combobox">
- <combo_box.item label="システムデフォルト" name="System Default Language"/>
<combo_box.item label="English (英語)" name="English"/>
<combo_box.item label="Dansk (デンマーク語) - ベータ" name="Danish"/>
<combo_box.item label="Deutsch (ドイツ語) – ベータ" name="Deutsch(German)"/>
diff --git a/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml b/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml
index ebaab7c122..04dfc0176d 100644
--- a/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="panel_snapshot_options">
<button label="ディスクã«ä¿å­˜" name="save_to_computer_btn"/>
- <button label="æŒã¡ç‰©ã«ä¿å­˜ï¼ˆL$[Amount])" name="save_to_inventory_btn"/>
+ <button label="æŒã¡ç‰©ã«ä¿å­˜ï¼ˆL$[AMOUNT])" name="save_to_inventory_btn"/>
<button label="プロフィールフィードã§å…±æœ‰ã™ã‚‹" name="save_to_profile_btn"/>
<button label="Facebook ã§å…±æœ‰ã™ã‚‹" name="send_to_facebook_btn"/>
<button label="Twitter ã§å…±æœ‰ã™ã‚‹" name="send_to_twitter_btn"/>
diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml
index bcf4698bb0..9116bba8bb 100644
--- a/indra/newview/skins/default/xui/ja/strings.xml
+++ b/indra/newview/skins/default/xui/ja/strings.xml
@@ -5739,4 +5739,25 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンロードã—ã¦ãã ã
<string name="Mav_Details_MAV_UNKNOWN_VERSION">
物ç†å½¢çŠ¶ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“。物ç†ãƒ¢ãƒ‡ãƒ«ã«æ­£ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’設定ã—ã¦ãã ã•ã„。
</string>
+ <string name="couldnt_resolve_host">
+ DNS ãŒãƒ›ã‚¹ãƒˆå ([HOSTNAME]) を解決ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚
+www.secondlife.com ã®ã‚¦ã‚§ãƒ–サイトã«æŽ¥ç¶šã§ãã‚‹ã‹ã”確èªãã ã•ã„。
+接続ã§ãã¦ã‚‚ã€ã“ã®ã‚¨ãƒ©ãƒ¼ãŒç¶™ç¶šçš„ã«èµ·ã“ã‚‹å ´åˆã¯ã€
+サãƒãƒ¼ãƒˆã‚»ã‚¯ã‚·ãƒ§ãƒ³ã‹ã‚‰å•é¡Œã‚’報告ã—ã¦ãã ã•ã„。
+ </string>
+ <string name="ssl_peer_certificate">
+ ログインサーãƒãƒ¼ãŒ SSL 経由ã§ç¢ºèªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚
+ã“ã®ã‚¨ãƒ©ãƒ¼ãŒç¶™ç¶šçš„ã«èµ·ã“ã‚‹å ´åˆã¯ã€
+Secondlife.com ã®ã‚µãƒãƒ¼ãƒˆã‚»ã‚¯ã‚·ãƒ§ãƒ³ã‹ã‚‰
+å•é¡Œã‚’報告ã—ã¦ãã ã•ã„。
+ </string>
+ <string name="ssl_connect_error">
+ ã“ã®å•é¡Œã®å¤šãã¯ã€ãŠä½¿ã„ã®ã‚³ãƒ³ãƒ”ュータã®æ™‚計ãŒæ­£ã—ã設定ã•ã‚Œã¦ã„ãªã„ãŸã‚ã«èµ·ã“ã‚Šã¾ã™ã€‚
+コントロールパãƒãƒ«ã‹ã‚‰æ™‚刻ã¨æ—¥ä»˜ãŒæ­£ã—ã設定ã•ã‚Œã¦ã„ã‚‹ã‹ã”確èªãã ã•ã„。
+ãŠä½¿ã„ã®ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã¨ãƒ•ã‚¡ã‚¤ã‚¢ã‚¦ã‚©ãƒ¼ãƒ«ã‚‚æ­£ã—ã設定ã•ã‚Œã¦ã„ã‚‹ã‹ãŠç¢ºã‹ã‚ãã ã•ã„。
+ã“ã®ã‚¨ãƒ©ãƒ¼ãŒç¶™ç¶šçš„ã«èµ·ã“ã‚‹å ´åˆã¯ã€Secondlife.com ã®ã‚µãƒãƒ¼ãƒˆã‚»ã‚¯ã‚·ãƒ§ãƒ³ã‹ã‚‰
+å•é¡Œã‚’報告ã—ã¦ãã ã•ã„。
+
+[https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 ナレッジベース]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_general.xml b/indra/newview/skins/default/xui/pl/panel_preferences_general.xml
index 082dc0687e..55df13e7ac 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_general.xml
@@ -4,7 +4,6 @@
Język:
</text>
<combo_box name="language_combobox">
- <combo_box.item label="Domyślny" name="System Default Language" />
<combo_box.item label="English (Angielski)" name="English" />
<combo_box.item label="Dansk (Duński) - Beta" name="Danish" />
<combo_box.item label="Deutsch (Niemiecki) - Beta" name="Deutsch(German)" />
diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml
index 5c848034d8..b4cf0a1b20 100644
--- a/indra/newview/skins/default/xui/pt/notifications.xml
+++ b/indra/newview/skins/default/xui/pt/notifications.xml
@@ -243,6 +243,10 @@ Por favor, selecione apenas um objeto e tente novamente.
Nota: Ao ativar esta opção, qualquer pessoa que utilizar este computador poderá ver a sua lista de lugares preferidos.
<usetemplate name="okbutton" yestext="OK"/>
</notification>
+ <notification name="AllowMultipleViewers">
+ Não é possível executar múltiplos visualizadores Second Life. Pode levar a uma falha, um corrompimento, visuais alterados e falha no desempenho no cache de textura.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="GrantModifyRights">
Conceder direitos de modificação a outros residentes vai autorizá-los a mudar, apagar ou pegar TODOS os seus objetos. Seja MUITO cuidadoso ao conceder esta autorização.
Deseja dar direitos de modificação a [NAME]?
@@ -711,9 +715,9 @@ Para aumentar a qualidade do vídeo, vá para Preferências &gt; Vídeo.
Você não está autorizado a terraplanar o terreno [PARCEL].
</notification>
<notification name="CannotCopyWarning">
- Você não tem autorização para copiar os itens abaixo:
-[ITEMS]
-ao dá-los, você ficará sem eles no seu inventário. Deseja realmente dar estes itens?
+ Não existe autorização para copiar os itens abaixo:
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
+e eles sairão do inverntário se sair. Deseja realmente dar estes itens?
<usetemplate name="okcancelbuttons" notext="Não" yestext="Sim"/>
</notification>
<notification name="CannotGiveItem">
@@ -3702,13 +3706,13 @@ ele não está na mesma região que você.
Você não pode criar árvores e grama em terrenos que não são sua propriedade.
</notification>
<notification name="NoCopyPermsNoObject">
- A cópia falhou porque você não está autorizado a copiar o objeto &apos;[OBJ_NAME]&apos;.
+ Falha na cópia por falta de permissão para copiar o objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoTransPermsNoObject">
- A cópia falhou porque o objeto &apos;[OBJ_NAME]&apos; não pode ser transferido para você.
+ Falha na cópia, porque o objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; não pode ser transferido para você.
</notification>
<notification name="AddToNavMeshNoCopy">
- A cópia falhou porque o objeto &apos;[OBJ_NAME]&apos; contribui para o navmesh.
+ Falha na cópia, porque o objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; contribui para o Navmesh.
</notification>
<notification name="DupeWithNoRootsSelected">
Duplicar sem objetos raiz selecionados.
@@ -3753,34 +3757,34 @@ Tente novamente em instantes.
Salvar no inventário foi desativado.
</notification>
<notification name="NoExistNoSaveToContents">
- Não é possível salvar &apos;[OBJ_NAME]&apos; no conteúdo do objeto porque o objeto do qual ele foi renderizado não existe mais.
+ Não foi possível salvar &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; para os conteúdos do objeto, porque o objeto foi utilizado e não existe mais.
</notification>
<notification name="NoModNoSaveToContents">
- Não é possível salvar &apos;[OBJ_NAME]&apos; no conteúdo do objeto porque você não tem permissão para modificar o objeto &apos;[DEST_NAME]&apos;.
+ Não foi possível salvar &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; para os conteúdos do objeto, porque você não tem permissão para modificar o objeto &lt;nolink&gt;&apos;[DEST_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoSaveBackToInvDisabled">
- Não é possível salvar &apos;[OBJ_NAME]&apos; no inventário -- essa operação foi desativada.
+ Não é possível salvar &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; no inventário outra vez -- esta operação foi desabilitada.
</notification>
<notification name="NoCopyNoSelCopy">
- Você não pode copiar sua seleção porque não está autorizado a copiar o objeto &apos;[OBJ_NAME]&apos;.
+ Não é possível copiar a seleção porque você não tem permissão para copiar o objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoTransNoSelCopy">
- Você não pode copiar a seleção porque o objeto &apos;[OBJ_NAME]&apos; não é transferível.
+ Não é possível copiar a seleção porque o objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; não é transferível.
</notification>
<notification name="NoTransNoCopy">
- Você não pode copiar a seleção porque o objeto &apos;[OBJ_NAME]&apos; não é transferível.
+ Não é possível copiar a seleção porque o objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; não é transferível.
</notification>
<notification name="NoPermsNoRemoval">
- A remoção do objeto &apos;[OBJ_NAME]&apos; do simulador é proibida pelo sistema de permissões.
+ A remoção do objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; do simulador não é permitida pelo sistema de permissão.
</notification>
<notification name="NoModNoSaveSelection">
- Você não pode salvar sua seleção porque não está autorizado a modificar o objeto &apos;[OBJ_NAME]&apos;.
+ Não é possível salvar a seleção porque você não tem permissão para modificar o objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoCopyNoSaveSelection">
- Não é possível salvar sua seleção porque o objeto &apos;[OBJ_NAME]&apos; não é copiável.
+ Não é possível salvar a seleção porque o objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; não é copiável.
</notification>
<notification name="NoModNoTaking">
- Você não pode levar sua seleção porque não está autorizado a modificar o objeto &apos;[OBJ_NAME]&apos;.
+ Não é possível realizar a seleção porque você não tem permissão para modificar o objeto &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="RezDestInternalError">
Erro interno: tipo de destino desconhecido.
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_general.xml b/indra/newview/skins/default/xui/pt/panel_preferences_general.xml
index 68fbd049b1..915d695605 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_general.xml
@@ -4,7 +4,6 @@
Idioma:
</text>
<combo_box name="language_combobox">
- <combo_box.item label="Padrão" name="System Default Language"/>
<combo_box.item label="English (Inglês)" name="English"/>
<combo_box.item label="Dansk (Dinamarquês) - Beta" name="Danish"/>
<combo_box.item label="Deutsch (Alemão) - Beta" name="Deutsch(German)"/>
diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml
index ecf90ef787..4151ef36ac 100644
--- a/indra/newview/skins/default/xui/pt/strings.xml
+++ b/indra/newview/skins/default/xui/pt/strings.xml
@@ -5615,4 +5615,25 @@ Tente colocar o caminho do editor entre aspas.
<string name="Mav_Details_MAV_UNKNOWN_VERSION">
A forma física não tem a versão correta. Defina a versão correta para o modelo físico.
</string>
+ <string name="couldnt_resolve_host">
+ O DNS não pode resolver o nome do host([HOSTNAME]).
+Verifique se você pode conectar ao site www.secondlife.com . Se você
+puder, mas se continuar recebendo esta mensagem de erro, vá à sessão
+Suporte no site Secondlife.com e informe o problema.
+ </string>
+ <string name="ssl_peer_certificate">
+ O servidor de acesso não pôde verificá-lo pelo SSL.
+Se você continuar recebendo esta mensagem de erro,
+vá à sessão Suporte no site Secondlife.com
+e informe o problema.
+ </string>
+ <string name="ssl_connect_error">
+ Geralmente, esse erro significa que o relógio do seu computador não está com o horário correto.
+Vá em Painel de Controles e certifique-se de que a hora e data estejam corretos.
+Além disso, verifique se a sua rede e firewall estejam corretos. Se você continuar
+recebendo esta mensagem de erro, vá à sessão Suporte no site Secondlife.com
+e informe o problema.
+
+[https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 Base de conhecimento]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml
index d752bf254e..d6866b6489 100644
--- a/indra/newview/skins/default/xui/ru/notifications.xml
+++ b/indra/newview/skins/default/xui/ru/notifications.xml
@@ -244,6 +244,10 @@
Примечание. ПоÑле Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ñтой опции вÑе пользователи данного компьютера Ñмогут увидеть ÑпиÑок ваших избранных меÑÑ‚.
<usetemplate name="okbutton" yestext="OK"/>
</notification>
+ <notification name="AllowMultipleViewers">
+ ЗапуÑк неÑкольких приложений Second Life Viewer не поддерживаетÑÑ. Это может привеÑти к конфликтам кÑша текÑтур, повреждению и Ñнижению производительноÑти и визуального отображениÑ.
+ <usetemplate name="okbutton" yestext="ОК"/>
+ </notification>
<notification name="GrantModifyRights">
ПредоÑтавление другому жителю прав на изменение позволит ему изменÑÑ‚ÑŒ, удалÑÑ‚ÑŒ или брать ЛЮБЫЕ ваши объекты. Будьте ОЧЕÐЬ оÑторожны Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñтавлением такого разрешениÑ.
Дать пользователю [NAME] права на изменение?
@@ -717,9 +721,9 @@
Вам не разрешено терраформировать учаÑток [PARCEL].
</notification>
<notification name="CannotCopyWarning">
- У Ð²Ð°Ñ Ð½ÐµÑ‚ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° копирование Ñледующих предметов:
-[ITEMS]
-ЕÑли вы отдадите Ñти вещи, их больше не будет в вашем инвентаре. Ð’Ñ‹ дейÑтвительно хотите предложить Ñти предметы?
+ У Ð²Ð°Ñ Ð½ÐµÑ‚ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° копирование Ñледующих предметов:
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
+и они пропадут из вашего инвентарÑ, еÑли вы их отдадите. Ð’Ñ‹ дейÑтвительно хотите предложить Ñти предметы?
<usetemplate name="okcancelbuttons" notext="Ðет" yestext="Да"/>
</notification>
<notification name="CannotGiveItem">
@@ -3715,13 +3719,13 @@
Ð’Ñ‹ не можете Ñоздавать Ð´ÐµÑ€ÐµÐ²ÑŒÑ Ð¸ траву на чужой земле.
</notification>
<notification name="NoCopyPermsNoObject">
- Ðе удалоÑÑŒ Ñкопировать: вам не разрешено копировать объект «[OBJ_NAME]».
+ Ðе удалоÑÑŒ Ñкопировать, потому что у Ð²Ð°Ñ Ð½ÐµÑ‚ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° копирование Ñтого предмета &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoTransPermsNoObject">
- Ðе удалоÑÑŒ Ñкопировать: объект «[OBJ_NAME]» Ð½ÐµÐ»ÑŒÐ·Ñ Ð¿ÐµÑ€ÐµÐ½ÐµÑти к вам.
+ Ðе удалоÑÑŒ Ñкопировать, потому что предмет &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; не может быть перемещён к вам.
</notification>
<notification name="AddToNavMeshNoCopy">
- Ðе удалоÑÑŒ Ñкопировать: объект «[OBJ_NAME]» отноÑитÑÑ Ðº навигационной Ñетке.
+ Ðе удалоÑÑŒ Ñкопировать, потому что предмет &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; отноÑитÑÑ Ðº навигационной Ñетке.
</notification>
<notification name="DupeWithNoRootsSelected">
Выбран дубликат без корневых объектов.
@@ -3766,34 +3770,34 @@
Сохранение в инвентаре отключено.
</notification>
<notification name="NoExistNoSaveToContents">
- ÐÐµÐ»ÑŒÐ·Ñ Ñохранить «[OBJ_NAME]» в Ñодержимом объекта: объект, из которого оно было выложено, уже не ÑущеÑтвует.
+ Ðе удалоÑÑŒ Ñохранить &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; в Ñодержимом предмета, потому что меÑто, в котором был Ñоздан предмет, больше не ÑущеÑтвует.
</notification>
<notification name="NoModNoSaveToContents">
- ÐÐµÐ»ÑŒÐ·Ñ Ñохранить «[OBJ_NAME]» в Ñодержимом объекта: вам не разрешено изменÑÑ‚ÑŒ объект «[DEST_NAME]».
+ Ðе удалоÑÑŒ Ñохранить &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; в Ñодержимом предмета, потому что у Ð²Ð°Ñ Ð½ÐµÑ‚ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° модификацию предмета &lt;nolink&gt;&apos;[DEST_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoSaveBackToInvDisabled">
- Ðевозможно Ñохранить «[OBJ_NAME]» в инвентаре: Ñта Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð·Ð°Ð¿Ñ€ÐµÑ‰ÐµÐ½Ð°.
+ Ðе удалоÑÑŒ Ñохранить &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; обратно в инвентаре – Ñта Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð°.
</notification>
<notification name="NoCopyNoSelCopy">
- ÐÐµÐ»ÑŒÐ·Ñ Ñкопировать выбранное: вам не разрешено копировать объект «[OBJ_NAME]».
+ Ð’Ñ‹ не можете Ñкопировать выбор, потому что у Ð²Ð°Ñ Ð½ÐµÑ‚ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° копирование Ñтого предмета &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoTransNoSelCopy">
- Ðевозможно Ñкопировать выбранный предмет: объект «[OBJ_NAME]» не переноÑитÑÑ.
+ Ð’Ñ‹ не можете Ñкопировать Ñвой выбор, потому что предмет &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; не может быть перемещён.
</notification>
<notification name="NoTransNoCopy">
- Ðевозможно Ñкопировать выбранный предмет: объект «[OBJ_NAME]» не переноÑитÑÑ.
+ Ð’Ñ‹ не можете Ñкопировать Ñвой выбор, потому что предмет &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; не может быть перемещён.
</notification>
<notification name="NoPermsNoRemoval">
- Удаление объекта «[OBJ_NAME]» из ÑимулÑтора запрещено ÑиÑтемой разрешений.
+ Удаление предмета &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; из ÑимулÑтора не допущено ÑиÑтемой прав доÑтупа.
</notification>
<notification name="NoModNoSaveSelection">
- ÐÐµÐ»ÑŒÐ·Ñ Ñохранить выбранное: вам не разрешено изменÑÑ‚ÑŒ объект «[OBJ_NAME]».
+ Копирование выбора невозможно, потому что у Ð²Ð°Ñ Ð½ÐµÑ‚ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° модифицирование Ñтого предмета &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="NoCopyNoSaveSelection">
- Ðевозможно Ñохранить выбранный предмет: объект «[OBJ_NAME]» не копируетÑÑ.
+ Ð’Ñ‹ не можете Ñохранить Ñвой выбор, потому что предмет &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; не поддаётÑÑ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸ÑŽ.
</notification>
<notification name="NoModNoTaking">
- ÐÐµÐ»ÑŒÐ·Ñ Ð·Ð°Ð±Ñ€Ð°Ñ‚ÑŒ выбранное: вам не разрешено изменÑÑ‚ÑŒ объект «[OBJ_NAME]».
+ Ð’Ñ‹ не можете Ñкопировать Ñвой выбор, потому что у Ð²Ð°Ñ Ð½ÐµÑ‚ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° модифицирование Ñтого предмета &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;.
</notification>
<notification name="RezDestInternalError">
ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°: неизвеÑтный тип меÑта назначениÑ.
diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_general.xml b/indra/newview/skins/default/xui/ru/panel_preferences_general.xml
index b15d0e3abf..918b042dd7 100644
--- a/indra/newview/skins/default/xui/ru/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/ru/panel_preferences_general.xml
@@ -4,7 +4,6 @@
Язык:
</text>
<combo_box name="language_combobox">
- <combo_box.item label="Язык ÑиÑтемы" name="System Default Language"/>
<combo_box.item label="English - ÐнглийÑкий" name="English"/>
<combo_box.item label="Dansk – датÑкий (бета-верÑиÑ)" name="Danish"/>
<combo_box.item label="Deutsch – немецкий (бета-верÑиÑ)" name="Deutsch(German)"/>
diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml
index 267c717189..dcc503f18c 100644
--- a/indra/newview/skins/default/xui/ru/strings.xml
+++ b/indra/newview/skins/default/xui/ru/strings.xml
@@ -5747,4 +5747,25 @@ support@secondlife.com.
<string name="Mav_Details_MAV_UNKNOWN_VERSION">
У физичеÑкой формы нет правильной верÑии. Задайте правильную верÑию Ð´Ð»Ñ Ñ„Ð¸Ð·Ð¸Ñ‡ÐµÑкой модели.
</string>
+ <string name="couldnt_resolve_host">
+ DNS не удалоÑÑŒ разрешить Ð¸Ð¼Ñ ÑƒÐ·Ð»Ð°([HOSTNAME]).
+Проверьте возможноÑÑ‚ÑŒ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº веб-Ñайту www.secondlife.com.
+ЕÑли вы продолжаете получать Ñту ошибку, перейдите в раздел
+поддержки и Ñообщите о проблеме.
+ </string>
+ <string name="ssl_peer_certificate">
+ Серверу входа в ÑиÑтему не удалоÑÑŒ пройти аутентификацию Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ
+протокола SSL. ЕÑли вы продолжаете получать Ñту ошибку,
+перейдите в раздел поддержки на веб-Ñайте SecondLife.com
+и Ñообщите о проблеме.
+ </string>
+ <string name="ssl_connect_error">
+ ЧаÑто Ñто означает, что чаÑÑ‹ компьютера уÑтановлены неправильно.
+Перейдите, пожалуйÑта, на Панели ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸ убедитеÑÑŒ в правильной
+уÑтановке времени и даты. Также проверьте правильноÑÑ‚ÑŒ наÑтройки Ñети
+и брандмауÑра. ЕÑли вы продолжаете получать Ñту ошибку, перейдите в
+раздел поддержки на веб-Ñайте SecondLife.com и Ñообщите о проблеме.
+
+[https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 База знаний]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/tr/notifications.xml b/indra/newview/skins/default/xui/tr/notifications.xml
index d72d89f1f5..fce5bbfcab 100644
--- a/indra/newview/skins/default/xui/tr/notifications.xml
+++ b/indra/newview/skins/default/xui/tr/notifications.xml
@@ -244,6 +244,10 @@ Lütfen sadece bir nesne seçin ve tekrar deneyin.
Not: Bu seçeneği etkinleştirdiğinizde, bu bilgisayarı kullanan herkes en sevdiğiniz konumlar listenizi görebilecek.
<usetemplate name="okbutton" yestext="Tamam"/>
</notification>
+ <notification name="AllowMultipleViewers">
+ Birden çok Second Life görüntüleyiciyi çalıştırma özelliği desteklenmiyor. Bu durum doku önbelleği çakışmalarına, görsellerin bozulmasına ve performansın düşmesine yol açabilir.
+ <usetemplate name="okbutton" yestext="Tamam"/>
+ </notification>
<notification name="GrantModifyRights">
Başka bir Sakine değişiklik yapma hakkı verdiğinizde, SL dünyasında sahip olduğunuz HERHANGİ BİR nesneyi değiştirebilme, silebilme veya alabilmelerine izin vermiş olursunuz. Bu izni verirken ÇOK dikkatli olun.
[NAME] adlı kişiye değişiklik yapma hakkı vermek istiyor musunuz?
@@ -718,9 +722,9 @@ Grafik Kalitesi, Tercihler &gt; Grafikler sekmesinden yükseltilebilir.
[PARCEL] parseli üzerinde yer şekillendirmesi yapma izniniz bulunmuyor.
</notification>
<notification name="CannotCopyWarning">
- Aşağıdaki öğeleri kopyalamak için gerekli izne sahip değilsiniz:
-[ITEMS]
-Bu öğeleri verdiğiniz takdirde envanterinizden çıkacaklar. Bu öğeleri teklif etmeyi gerçekten istiyor musunuz?
+ Aşağıdaki öğeleri kopyalama izniniz yok:
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
+ve bunları elden çıkardığınız takdirde envanterinizden kaybolacaktır. Bu öğeleri sunmayı gerçekten istiyor musunuz?
<usetemplate name="okcancelbuttons" notext="Hayır" yestext="Evet"/>
</notification>
<notification name="CannotGiveItem">
@@ -3714,13 +3718,13 @@ GiriÅŸim iptal edildi.
Sahibi olmadığınız arazide ağaçlar ve çimen oluşturamazsınız.
</notification>
<notification name="NoCopyPermsNoObject">
- &apos;[OBJ_NAME]&apos; nesnesini kopyalama izniniz olmadığı için kopyalama başarılamadı.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesnesini kopyalama izniniz olmadığından kopyalama başarısız oldu.
</notification>
<notification name="NoTransPermsNoObject">
- &apos;[OBJ_NAME]&apos; nesnesi size aktarılamadığı için kopyalama başarılamadı.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesnesi size devredilemediğinden kopyalama başarısız oldu.
</notification>
<notification name="AddToNavMeshNoCopy">
- &apos;[OBJ_NAME]&apos; nesnesi navmesh&apos;e katkıda bulunduğu için kopyalama başarılamadı.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesnesi navigasyon örgüsüne katkıda bulunduğundan kopyalama başarısız oldu.
</notification>
<notification name="DupeWithNoRootsSelected">
Kök nesne seçili olmayan kopya.
@@ -3765,34 +3769,34 @@ Lütfen bir dakika sonra tekrar deneyin.
Envantere Geri Kaydet devre dışı bırakıldı.
</notification>
<notification name="NoExistNoSaveToContents">
- &apos;[OBJ_NAME]&apos; nesne içeriğine kaydedilemedi, çünkü oluşturulurken temel alınan nesne artık mevcut değil.
+ Yeniden canlandırıldığı nesne artık mevcut olmadığından &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesne içeriklerine kaydedilemiyor.
</notification>
<notification name="NoModNoSaveToContents">
- &apos;[DEST_NAME]&apos; nesnesini değiştirme izniniz olmadığı için &apos;[OBJ_NAME]&apos; nesne içeriğine kaydedilemedi.
+ &lt;nolink&gt;&apos;[DEST_NAME]&apos;&lt;/nolink&gt; nesnesini değiştirme izniniz olmadığından &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesne içeriklerine kaydedilemiyor.
</notification>
<notification name="NoSaveBackToInvDisabled">
- &apos;[OBJ_NAME]&apos; envantere geri kaydedilemez -- bu işlem devre dışı bırakıldı.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; envantere tekrar kaydedilemiyor -- bu işlem devre dışı bırakılmış.
</notification>
<notification name="NoCopyNoSelCopy">
- &apos;[OBJ_NAME]&apos; nesnesini kopyalama izniniz olmadığı için seçiminizi kopyalamayazsınız.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesnesini kopyalama izniniz olmadığından seçiminizi kopyalayamazsınız.
</notification>
<notification name="NoTransNoSelCopy">
- &apos;[OBJ_NAME]&apos; nesnesi aktarılamaz olduğu için seçiminizi kopyalayamazsınız.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesnesi devredilebilir olmadığından seçiminizi kopyalayamazsınız.
</notification>
<notification name="NoTransNoCopy">
- &apos;[OBJ_NAME]&apos; nesnesi aktarılamaz olduğu için seçiminizi kopyalayamazsınız.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesnesi devredilebilir olmadığından seçiminizi kopyalayamazsınız.
</notification>
<notification name="NoPermsNoRemoval">
- Benzeticiden &apos;[OBJ_NAME]&apos; nesnesinin kaldırılmasına izinler sistemi izin vermiyor.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesnesinin simülatörden kaldırılmasına izin sistemi tarafından izin verilmiyor.
</notification>
<notification name="NoModNoSaveSelection">
- &apos;[OBJ_NAME]&apos; nesnesini değiştirme izniniz olmadığı için seçiminizi kaydedemezsiniz.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesnesini değiştirme izniniz olmadığından seçiminiz kaydedilemiyor.
</notification>
<notification name="NoCopyNoSaveSelection">
- &apos;[OBJ_NAME]&apos; nesnesi kopyalanamaz olduğu için seçiminizi kaydedemezsiniz.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesnesi kopyalanabilir olmadığından seçiminiz kaydedilemiyor.
</notification>
<notification name="NoModNoTaking">
- &apos;[OBJ_NAME]&apos; nesnesini değiştirme izniniz olmadığı için seçiminizi alamazsınız.
+ &lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt; nesnesini değiştirme izniniz olmadığından seçiminizi alamazsınız.
</notification>
<notification name="RezDestInternalError">
Dahili Hata: Bilinmeyen hedef türü.
diff --git a/indra/newview/skins/default/xui/tr/panel_preferences_general.xml b/indra/newview/skins/default/xui/tr/panel_preferences_general.xml
index 2c05e8a47a..cec7a67f2f 100644
--- a/indra/newview/skins/default/xui/tr/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/tr/panel_preferences_general.xml
@@ -4,7 +4,6 @@
Dil:
</text>
<combo_box name="language_combobox">
- <combo_box.item label="Sistem varsayılanı" name="System Default Language"/>
<combo_box.item label="English (Ä°ngilizce)" name="English"/>
<combo_box.item label="Dansk (Danca) - Beta" name="Danish"/>
<combo_box.item label="Deutsch (Almanca) - Beta" name="Deutsch(German)"/>
diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml
index b574420793..ea6f2115e4 100644
--- a/indra/newview/skins/default/xui/tr/strings.xml
+++ b/indra/newview/skins/default/xui/tr/strings.xml
@@ -5748,4 +5748,25 @@ Düzenleyici yolunu çift tırnakla çevrelemeyi deneyin.
<string name="Mav_Details_MAV_UNKNOWN_VERSION">
Fiziksel şekil doğru sürüme sahip değil. Fiziksel model için doğru sürümü ayarlayın.
</string>
+ <string name="couldnt_resolve_host">
+ DNS sunucusu ana bilgisayar adını çözümleyemedi ([HOSTNAME]).
+Lütfen www.secondlife.com web sitesine bağlanabildiğinizi doğrulayın.
+Bağlanabiliyor, ancak bu hatayı almaya devam ediyorsanız, lütfen
+destek bölümüne gidin ve bu sorunu bildirin.
+ </string>
+ <string name="ssl_peer_certificate">
+ Oturum açma sunucusu SSL aracılığıyla kendini doğrulayamadı.
+Bu hatayı almaya devam ederseniz, lütfen
+SecondLife.com web sitesinin Destek
+bölümüne gidin ve sorunu bildirin.
+ </string>
+ <string name="ssl_connect_error">
+ Çoğunlukla, bu durum, bilgisayarınızın saatinin yanlış ayarlandığı anlamına gelir.
+Lütfen Denetim Masası&apos;na gidin ve tarih ve saat ayarlarının doğru yapıldığından emin olun.
+Ayrıca, ağınızın ve güvenlik duvarınızın doğru şekilde ayarlanıp ayarlanmadığını kontrol edin.
+Bu hatayı almaya devam ederseniz, lütfen SecondLife.com web sitesinin Destek bölümüne
+gidin ve sorunu bildirin.
+
+[https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 Bilgi Bankası]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/zh/floater_tos.xml b/indra/newview/skins/default/xui/zh/floater_tos.xml
index 4cac07cd21..2f02316fc0 100644
--- a/indra/newview/skins/default/xui/zh/floater_tos.xml
+++ b/indra/newview/skins/default/xui/zh/floater_tos.xml
@@ -4,7 +4,7 @@
http://secondlife.com/app/tos/
</floater.string>
<floater.string name="loading_url">
- data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E 正在載入 %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E
+ data:text/html;charset=utf-8,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E 正在載入 %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E
</floater.string>
<text name="tos_heading">
請閱讀並éµå®ˆSecond Life使用æ¢æ¬¾ã€éš±ç§æ”¿ç­–ã€æœå‹™æ¢æ¬¾ï¼ŒåŒ…括åŒæ„在發生爭議時接å—仲è£ä¸¦æ”¾æ£„採å–集體或群體求訴的è¦å®šã€‚ 繼續登入[SECOND_LIFE]å‰ï¼Œä½ å¿…é ˆåŒæ„這些æ¢æ¬¾ã€‚
diff --git a/indra/newview/skins/default/xui/zh/notifications.xml b/indra/newview/skins/default/xui/zh/notifications.xml
index 9fe7b5acae..120ed1e7d2 100644
--- a/indra/newview/skins/default/xui/zh/notifications.xml
+++ b/indra/newview/skins/default/xui/zh/notifications.xml
@@ -244,6 +244,10 @@
注æ„:你一旦åŒæ„這é¸é …,任何使用這部電腦的人都å¯çœ‹åˆ°ä½ æœ‰å“ªäº›ã€Œæœ€æ„›ã€åœ°é»žã€‚
<usetemplate name="okbutton" yestext="確定"/>
</notification>
+ <notification name="AllowMultipleViewers">
+ ä¸æ”¯æ´åŒæ™‚執行多個Second Lifeç€è¦½å™¨ã€‚ 這麼åšå¯èƒ½å°Žè‡´æ質快å–相互碰撞ã€æ¯€æ,並é™ä½Žè¦–覺效果åŠæ€§èƒ½ã€‚
+ <usetemplate name="okbutton" yestext="確定"/>
+ </notification>
<notification name="GrantModifyRights">
賦予å¦ä¸€å±…民「修改ã€æ¬Šï¼Œå°‡å…許他更改ã€åˆªé™¤æˆ–æ‹¿å–你在虛擬世界裡æ“有的任何物件。 賦予這項權é™æ™‚,敬請慎é‡è€ƒæ…®ã€‚
ä½ ä»è¦è³¦äºˆ [NAME] 修改權嗎?
@@ -719,7 +723,7 @@
</notification>
<notification name="CannotCopyWarning">
你沒有權é™è¤‡è£½ä»¥ä¸‹é …目:
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
如果你將它é€äººï¼Œå®ƒå°‡ç„¡æ³•çºŒç•™åœ¨æ”¶ç´å€ã€‚ 你確定è¦é€å‡ºé€™äº›æ±è¥¿å—Žï¼Ÿ
<usetemplate name="okcancelbuttons" notext="å¦" yestext="是"/>
</notification>
@@ -3714,13 +3718,13 @@ SHA1 指紋:[MD5_DIGEST]
你無法在別人的土地上建立樹和è‰ã€‚
</notification>
<notification name="NoCopyPermsNoObject">
- 複製失敗,你無權複製物件 &apos;[OBJ_NAME]&apos;。
+ 複製失敗,你無權複製物件&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;。
</notification>
<notification name="NoTransPermsNoObject">
- 複製失敗,因為物件 &apos;[OBJ_NAME]&apos; 無法轉移給你。
+ 複製失敗,因為物件&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;無法轉移給你。
</notification>
<notification name="AddToNavMeshNoCopy">
- 複製失敗,因為物件 &apos;[OBJ_NAME]&apos; å°å°Žèˆªç¶²é¢æœ‰è²¢ç»ã€‚
+ 複製失敗,因為物件&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;å°å°Žèˆªç¶²é¢æœ‰è²¢ç»ã€‚
</notification>
<notification name="DupeWithNoRootsSelected">
é¸å–了沒有根的é‡è¦†ç‰©ä»¶ã€‚
@@ -3765,34 +3769,34 @@ SHA1 指紋:[MD5_DIGEST]
「儲存回收ç´å€ã€åŠŸèƒ½å·²è¢«åœç”¨ã€‚
</notification>
<notification name="NoExistNoSaveToContents">
- 無法將 &apos;[OBJ_NAME]&apos; 儲存到物件內容,因為產生它的來æºç‰©ä»¶å·²ä¸å­˜åœ¨ã€‚
+ 無法將&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;儲存到物件內容,因為產生它的來æºç‰©ä»¶å·²ä¸å­˜åœ¨ã€‚
</notification>
<notification name="NoModNoSaveToContents">
- 無法儲存 [OBJ_NAME] 到物件內容,你無權修改 &apos;[DEST_NAME]&apos; 物件。
+ 無法儲存&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;到物件內容,因爲你無權修改&lt;nolink&gt;&apos;[DEST_NAME]&apos;&lt;/nolink&gt;物件。
</notification>
<notification name="NoSaveBackToInvDisabled">
- 無法將 &apos;[OBJ_NAME]&apos; 儲存回收ç´å€ï¼Œæ­¤å‹•ä½œå·²è¢«åœç”¨ã€‚
+ 無法將&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;儲存回收ç´å€ï¼Œæ­¤å‹•ä½œå·²è¢«åœç”¨ã€‚
</notification>
<notification name="NoCopyNoSelCopy">
- 無法複製你所é¸çš„,因為你無權複製物件 &apos;[OBJ_NAME]&apos;。
+ 無法複製你所é¸çš„,因為你無權複製物件&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;。
</notification>
<notification name="NoTransNoSelCopy">
- 無法é¸å–複製,因為物件 &apos;[OBJ_NAME]&apos; ä¸å¯è½‰ç§»ã€‚
+ 無法é¸å–複製,因為物件&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;ä¸å¯è½‰ç§»ã€‚
</notification>
<notification name="NoTransNoCopy">
- 無法é¸å–複製,因為物件 &apos;[OBJ_NAME]&apos; ä¸å¯è½‰ç§»ã€‚
+ 無法é¸å–複製,因為物件&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;ä¸å¯è½‰ç§»ã€‚
</notification>
<notification name="NoPermsNoRemoval">
- 權é™ç³»çµ±ä¸å…許從模擬器移除物件 &apos;[OBJ_NAME]&apos;。
+ 權é™ç³»çµ±ä¸å…許從模擬器移除物件&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;。
</notification>
<notification name="NoModNoSaveSelection">
- 無法儲存你所é¸çš„,因為你無權修改 &apos;[OBJ_NAME]&apos; 物件。
+ 無法儲存你所é¸çš„,因為你無權修改&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;物件。
</notification>
<notification name="NoCopyNoSaveSelection">
- 無法儲存你所é¸çš„,因為物件 &apos;[OBJ_NAME]&apos; ä¸å¯è¤‡è£½ã€‚
+ 無法儲存你所é¸çš„,因為物件&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;ä¸å¯è¤‡è£½ã€‚
</notification>
<notification name="NoModNoTaking">
- 無法拿å–你所é¸çš„,因為你無權修改 &apos;[OBJ_NAME]&apos; 物件。
+ 無法å–用你所é¸çš„,因為你無權修改物件&lt;nolink&gt;&apos;[OBJ_NAME]&apos;&lt;/nolink&gt;。
</notification>
<notification name="RezDestInternalError">
內部錯誤:未知的目的地類型。
diff --git a/indra/newview/skins/default/xui/zh/panel_preferences_general.xml b/indra/newview/skins/default/xui/zh/panel_preferences_general.xml
index 20335d82ae..87c38e4346 100644
--- a/indra/newview/skins/default/xui/zh/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/zh/panel_preferences_general.xml
@@ -4,7 +4,6 @@
語言:
</text>
<combo_box name="language_combobox">
- <combo_box.item label="系統é è¨­" name="System Default Language"/>
<combo_box.item label="英語" name="English"/>
<combo_box.item label="Dansk(丹麥語)- 試用版" name="Danish"/>
<combo_box.item label="Deutsch(德語)- 試用版" name="Deutsch(German)"/>
diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml
index 24d8dc60cb..f8fd727145 100644
--- a/indra/newview/skins/default/xui/zh/strings.xml
+++ b/indra/newview/skins/default/xui/zh/strings.xml
@@ -5746,4 +5746,25 @@ http://secondlife.com/support 求助解決å•é¡Œã€‚
<string name="Mav_Details_MAV_UNKNOWN_VERSION">
物ç†å½¢ç‹€çš„版本ä¸æ­£ç¢ºã€‚ 請設æˆæ­£ç¢ºçš„物ç†æ¨¡åž‹ç‰ˆæœ¬ã€‚
</string>
+ <string name="couldnt_resolve_host">
+ DNS無法解決主機å稱([HOSTNAME])。
+請確èªä½ èƒ½å¤ é€£é€š www.secondlife.com
+網站。 如能連通,但繼續看到這個錯誤,
+請到「支æ´ã€éƒ¨åˆ†é€šå ±å•é¡Œã€‚
+ </string>
+ <string name="ssl_peer_certificate">
+ 登入伺æœå™¨ç„¡æ³•é€éŽSSL自我確èªã€‚
+如果你繼續看到這個錯誤,請å‰å¾€
+SecondLife.com網站的「支æ´ã€éƒ¨åˆ†
+æå ±å•é¡Œã€‚
+ </string>
+ <string name="ssl_connect_error">
+ 這通常æ„味你電腦的時é˜è¨­å®šä¸æ­£ç¢ºã€‚
+請到控制å°ç¢ºå®šæ™‚間和日期設定正確。
+並檢查確定你的網路和防ç«ç‰†è¨­å®šæ­£ç¢ºã€‚
+如果你繼續看到這個錯誤,請å‰å¾€SecondLife.com
+網站的「支æ´ã€éƒ¨åˆ†æå ±å•é¡Œã€‚
+
+[https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 知識庫]
+ </string>
</strings>
diff --git a/indra/newview/tests/llversioninfo_test.cpp b/indra/newview/tests/llversioninfo_test.cpp
index 2f7a4e9601..58f0469552 100644
--- a/indra/newview/tests/llversioninfo_test.cpp
+++ b/indra/newview/tests/llversioninfo_test.cpp
@@ -33,10 +33,8 @@
// LL_VIEWER_CHANNEL is a macro defined on the compiler command line. The
// macro expands to the string name of the channel, but without quotes. We
-// need to turn it into a quoted string. This macro trick does that.
-#define stringize_inner(x) #x
-#define stringize_outer(x) stringize_inner(x)
-#define ll_viewer_channel stringize_outer(LL_VIEWER_CHANNEL)
+// need to turn it into a quoted string. LL_TO_STRING() does that.
+#define ll_viewer_channel LL_TO_STRING(LL_VIEWER_CHANNEL)
namespace tut
{
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 541112a765..c0f642c852 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -26,19 +26,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
$/LicenseInfo$
"""
-import sys
-import os
-import os.path
-import shutil
import errno
import json
+import os
+import os.path
import plistlib
import random
import re
+import shutil
import stat
import subprocess
+import sys
import tarfile
import time
+import zipfile
viewer_dir = os.path.dirname(__file__)
# Add indra/lib/python to our path so we don't have to muck with PYTHONPATH.
@@ -63,7 +64,7 @@ class ViewerManifest(LLManifest):
self.path(src="../../etc/message.xml", dst="app_settings/message.xml")
if self.is_packaging_viewer():
- with self.prefix(src="app_settings"):
+ with self.prefix(src_dst="app_settings"):
self.exclude("logcontrol.xml")
self.exclude("logcontrol-dev.xml")
self.path("*.ini")
@@ -85,7 +86,7 @@ class ViewerManifest(LLManifest):
# ... and the included spell checking dictionaries
pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
- with self.prefix(src=pkgdir,dst=""):
+ with self.prefix(src=pkgdir):
self.path("dictionaries")
# include the extracted packages information (see BuildPackagesInfo.cmake)
@@ -107,17 +108,18 @@ class ViewerManifest(LLManifest):
Type='String',
Value=''))
settings_install = {}
- if 'sourceid' in self.args and self.args['sourceid']:
+ sourceid = self.args.get('sourceid')
+ if sourceid:
settings_install['sourceid'] = settings_template['sourceid'].copy()
- settings_install['sourceid']['Value'] = self.args['sourceid']
- print "Set sourceid in settings_install.xml to '%s'" % self.args['sourceid']
+ settings_install['sourceid']['Value'] = sourceid
+ print "Set sourceid in settings_install.xml to '%s'" % sourceid
- if 'channel_suffix' in self.args and self.args['channel_suffix']:
+ if self.args.get('channel_suffix'):
settings_install['CmdLineChannel'] = settings_template['CmdLineChannel'].copy()
settings_install['CmdLineChannel']['Value'] = self.channel_with_pkg_suffix()
print "Set CmdLineChannel in settings_install.xml to '%s'" % self.channel_with_pkg_suffix()
- if 'grid' in self.args and self.args['grid']:
+ if self.args.get('grid'):
settings_install['CmdLineGridChoice'] = settings_template['CmdLineGridChoice'].copy()
settings_install['CmdLineGridChoice']['Value'] = self.grid()
print "Set CmdLineGridChoice in settings_install.xml to '%s'" % self.grid()
@@ -129,20 +131,20 @@ class ViewerManifest(LLManifest):
src="environment")
- with self.prefix(src="character"):
+ with self.prefix(src_dst="character"):
self.path("*.llm")
self.path("*.xml")
self.path("*.tga")
# Include our fonts
- with self.prefix(src="fonts"):
+ with self.prefix(src_dst="fonts"):
self.path("*.ttf")
self.path("*.txt")
# skins
- with self.prefix(src="skins"):
+ with self.prefix(src_dst="skins"):
# include the entire textures directory recursively
- with self.prefix(src="*/textures"):
+ with self.prefix(src_dst="*/textures"):
self.path("*/*.tga")
self.path("*/*.j2c")
self.path("*/*.jpg")
@@ -170,7 +172,7 @@ class ViewerManifest(LLManifest):
# local_assets dir (for pre-cached textures)
- with self.prefix(src="local_assets"):
+ with self.prefix(src_dst="local_assets"):
self.path("*.j2c")
self.path("*.tga")
@@ -186,6 +188,10 @@ class ViewerManifest(LLManifest):
"Address Size":self.address_size,
"Update Service":"https://update.secondlife.com/update",
}
+ # Only store this if it's both present and non-empty
+ bugsplat_db = self.args.get('bugsplat')
+ if bugsplat_db:
+ build_data_dict["BugSplat DB"] = bugsplat_db
build_data_dict = self.finish_build_data_dict(build_data_dict)
with open(os.path.join(os.pardir,'build_data.json'), 'w') as build_data_handle:
json.dump(build_data_dict,build_data_handle)
@@ -206,8 +212,9 @@ class ViewerManifest(LLManifest):
def channel_with_pkg_suffix(self):
fullchannel=self.channel()
- if 'channel_suffix' in self.args and self.args['channel_suffix']:
- fullchannel+=' '+self.args['channel_suffix']
+ channel_suffix = self.args.get('channel_suffix')
+ if channel_suffix:
+ fullchannel+=' '+channel_suffix
return fullchannel
def channel_variant(self):
@@ -215,8 +222,7 @@ class ViewerManifest(LLManifest):
return self.channel().replace(CHANNEL_VENDOR_BASE, "").strip()
def channel_type(self): # returns 'release', 'beta', 'project', or 'test'
- global CHANNEL_VENDOR_BASE
- channel_qualifier=self.channel().replace(CHANNEL_VENDOR_BASE, "").lower().strip()
+ channel_qualifier=self.channel_variant().lower()
if channel_qualifier.startswith('release'):
channel_type='release'
elif channel_qualifier.startswith('beta'):
@@ -234,11 +240,12 @@ class ViewerManifest(LLManifest):
if self.channel_type() == 'release':
suffix=suffix.replace('Release', '').strip()
# for the base release viewer, suffix will now be null - for any other, append what remains
- if len(suffix) > 0:
- suffix = "_"+ ("_".join(suffix.split()))
+ if suffix:
+ suffix = "_".join([''] + suffix.split())
# the additional_packages mechanism adds more to the installer name (but not to the app name itself)
- if 'channel_suffix' in self.args and self.args['channel_suffix']:
- suffix+='_'+("_".join(self.args['channel_suffix'].split()))
+ # ''.split() produces empty list, so suffix only changes if
+ # channel_suffix is non-empty
+ suffix = "_".join([suffix] + self.args.get('channel_suffix', '').split())
return suffix
def installer_base_name(self):
@@ -424,7 +431,8 @@ class WindowsManifest(ViewerManifest):
def finish_build_data_dict(self, build_data_dict):
#MAINT-7294: Windows exe names depend on channel name, so write that in also
- build_data_dict.update({'Executable':self.final_exe()})
+ build_data_dict['Executable'] = self.final_exe()
+ build_data_dict['AppName'] = self.app_name()
return build_data_dict
def test_msvcrt_and_copy_action(self, src, dst):
@@ -470,7 +478,7 @@ class WindowsManifest(ViewerManifest):
pass
except NoMatchingAssemblyException as err:
pass
-
+
self.ccopy(src,dst)
else:
raise Exception("Directories are not supported by test_CRT_and_copy_action()")
@@ -488,24 +496,17 @@ class WindowsManifest(ViewerManifest):
# Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe.
self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe())
- with self.prefix(src=os.path.join(pkgdir, "VMP"), dst=""):
+ with self.prefix(src=os.path.join(pkgdir, "VMP")):
# include the compiled launcher scripts so that it gets included in the file_list
- self.path('SL_Launcher.exe')
- #IUM is not normally executed directly, just imported. No exe needed.
- self.path("InstallerUserMessage.py")
-
- with self.prefix(src=self.icon_path(), dst="vmp_icons"):
- self.path("secondlife.ico")
+ self.path('SLVersionChecker.exe')
- #VMP Tkinter icons
- with self.prefix("vmp_icons"):
- self.path("*.png")
- self.path("*.gif")
-
- #before, we only needed llbase at build time. With VMP, we need it at run time.
- with self.prefix(src=os.path.join(pkgdir, "lib", "python", "llbase"), dst="llbase"):
- self.path("*.py")
- self.path("_cllsd.so")
+ with self.prefix(dst="vmp_icons"):
+ with self.prefix(src=self.icon_path()):
+ self.path("secondlife.ico")
+ #VMP Tkinter icons
+ with self.prefix(src="vmp_icons"):
+ self.path("*.png")
+ self.path("*.gif")
# Plugin host application
self.path2basename(os.path.join(os.pardir,
@@ -513,8 +514,8 @@ class WindowsManifest(ViewerManifest):
"slplugin.exe")
# Get shared libs from the shared libs staging directory
- with self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']),
- dst=""):
+ with self.prefix(src=os.path.join(self.args['build'], os.pardir,
+ 'sharedlibs', self.args['configuration'])):
# Get llcommon and deps. If missing assume static linkage and continue.
try:
@@ -580,6 +581,17 @@ class WindowsManifest(ViewerManifest):
# Hunspell
self.path("libhunspell.dll")
+ # BugSplat
+ if self.args.get('bugsplat'):
+ if(self.address_size == 64):
+ self.path("BsSndRpt64.exe")
+ self.path("BugSplat64.dll")
+ self.path("BugSplatRc64.dll")
+ else:
+ self.path("BsSndRpt.exe")
+ self.path("BugSplat.dll")
+ self.path("BugSplatRc.dll")
+
# For google-perftools tcmalloc allocator.
try:
if self.args['configuration'].lower() == 'debug':
@@ -589,116 +601,118 @@ class WindowsManifest(ViewerManifest):
except:
print "Skipping libtcmalloc_minimal.dll"
-
self.path(src="licenses-win32.txt", dst="licenses.txt")
self.path("featuretable.txt")
- with self.prefix(src=pkgdir,dst=""):
+ with self.prefix(src=pkgdir):
self.path("ca-bundle.crt")
# Media plugins - CEF
- with self.prefix(src='../media_plugins/cef/%s' % self.args['configuration'], dst="llplugin"):
- self.path("media_plugin_cef.dll")
-
- # Media plugins - LibVLC
- with self.prefix(src='../media_plugins/libvlc/%s' % self.args['configuration'], dst="llplugin"):
- self.path("media_plugin_libvlc.dll")
-
- # Media plugins - Example (useful for debugging - not shipped with release viewer)
- if self.channel_type() != 'release':
- with self.prefix(src='../media_plugins/example/%s' % self.args['configuration'], dst="llplugin"):
- self.path("media_plugin_example.dll")
-
- # CEF runtime files - debug
- # CEF runtime files - not debug (release, relwithdebinfo etc.)
- config = 'debug' if self.args['configuration'].lower() == 'debug' else 'release'
- with self.prefix(src=os.path.join(pkgdir, 'bin', config), dst="llplugin"):
- self.path("chrome_elf.dll")
- self.path("d3dcompiler_43.dll")
- self.path("d3dcompiler_47.dll")
- self.path("libcef.dll")
- self.path("libEGL.dll")
- self.path("libGLESv2.dll")
- self.path("dullahan_host.exe")
- self.path("natives_blob.bin")
- self.path("snapshot_blob.bin")
- self.path("widevinecdmadapter.dll")
-
- # MSVC DLLs needed for CEF and have to be in same directory as plugin
- with self.prefix(src=os.path.join(os.pardir, 'sharedlibs', 'Release'), dst="llplugin"):
- self.path("msvcp120.dll")
- self.path("msvcr120.dll")
-
- # CEF files common to all configurations
- with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="llplugin"):
- self.path("cef.pak")
- self.path("cef_100_percent.pak")
- self.path("cef_200_percent.pak")
- self.path("cef_extensions.pak")
- self.path("devtools_resources.pak")
- self.path("icudtl.dat")
-
- with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst=os.path.join('llplugin', 'locales')):
- self.path("am.pak")
- self.path("ar.pak")
- self.path("bg.pak")
- self.path("bn.pak")
- self.path("ca.pak")
- self.path("cs.pak")
- self.path("da.pak")
- self.path("de.pak")
- self.path("el.pak")
- self.path("en-GB.pak")
- self.path("en-US.pak")
- self.path("es-419.pak")
- self.path("es.pak")
- self.path("et.pak")
- self.path("fa.pak")
- self.path("fi.pak")
- self.path("fil.pak")
- self.path("fr.pak")
- self.path("gu.pak")
- self.path("he.pak")
- self.path("hi.pak")
- self.path("hr.pak")
- self.path("hu.pak")
- self.path("id.pak")
- self.path("it.pak")
- self.path("ja.pak")
- self.path("kn.pak")
- self.path("ko.pak")
- self.path("lt.pak")
- self.path("lv.pak")
- self.path("ml.pak")
- self.path("mr.pak")
- self.path("ms.pak")
- self.path("nb.pak")
- self.path("nl.pak")
- self.path("pl.pak")
- self.path("pt-BR.pak")
- self.path("pt-PT.pak")
- self.path("ro.pak")
- self.path("ru.pak")
- self.path("sk.pak")
- self.path("sl.pak")
- self.path("sr.pak")
- self.path("sv.pak")
- self.path("sw.pak")
- self.path("ta.pak")
- self.path("te.pak")
- self.path("th.pak")
- self.path("tr.pak")
- self.path("uk.pak")
- self.path("vi.pak")
- self.path("zh-CN.pak")
- self.path("zh-TW.pak")
-
- with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="llplugin"):
- self.path("libvlc.dll")
- self.path("libvlccore.dll")
- self.path("plugins/")
-
- # pull in the crash logger and updater from other projects
+ with self.prefix(dst="llplugin"):
+ with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins')):
+ with self.prefix(src=os.path.join('cef', self.args['configuration'])):
+ self.path("media_plugin_cef.dll")
+
+ # Media plugins - LibVLC
+ with self.prefix(src=os.path.join('libvlc', self.args['configuration'])):
+ self.path("media_plugin_libvlc.dll")
+
+ # Media plugins - Example (useful for debugging - not shipped with release viewer)
+ if self.channel_type() != 'release':
+ with self.prefix(src=os.path.join('example', self.args['configuration'])):
+ self.path("media_plugin_example.dll")
+
+ # CEF runtime files - debug
+ # CEF runtime files - not debug (release, relwithdebinfo etc.)
+ config = 'debug' if self.args['configuration'].lower() == 'debug' else 'release'
+ with self.prefix(src=os.path.join(pkgdir, 'bin', config)):
+ self.path("chrome_elf.dll")
+ self.path("d3dcompiler_43.dll")
+ self.path("d3dcompiler_47.dll")
+ self.path("libcef.dll")
+ self.path("libEGL.dll")
+ self.path("libGLESv2.dll")
+ self.path("dullahan_host.exe")
+ self.path("natives_blob.bin")
+ self.path("snapshot_blob.bin")
+ self.path("widevinecdmadapter.dll")
+
+ # MSVC DLLs needed for CEF and have to be in same directory as plugin
+ with self.prefix(src=os.path.join(self.args['build'], os.pardir,
+ 'sharedlibs', 'Release')):
+ self.path("msvcp120.dll")
+ self.path("msvcr120.dll")
+
+ # CEF files common to all configurations
+ with self.prefix(src=os.path.join(pkgdir, 'resources')):
+ self.path("cef.pak")
+ self.path("cef_100_percent.pak")
+ self.path("cef_200_percent.pak")
+ self.path("cef_extensions.pak")
+ self.path("devtools_resources.pak")
+ self.path("icudtl.dat")
+
+ with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst='locales'):
+ self.path("am.pak")
+ self.path("ar.pak")
+ self.path("bg.pak")
+ self.path("bn.pak")
+ self.path("ca.pak")
+ self.path("cs.pak")
+ self.path("da.pak")
+ self.path("de.pak")
+ self.path("el.pak")
+ self.path("en-GB.pak")
+ self.path("en-US.pak")
+ self.path("es-419.pak")
+ self.path("es.pak")
+ self.path("et.pak")
+ self.path("fa.pak")
+ self.path("fi.pak")
+ self.path("fil.pak")
+ self.path("fr.pak")
+ self.path("gu.pak")
+ self.path("he.pak")
+ self.path("hi.pak")
+ self.path("hr.pak")
+ self.path("hu.pak")
+ self.path("id.pak")
+ self.path("it.pak")
+ self.path("ja.pak")
+ self.path("kn.pak")
+ self.path("ko.pak")
+ self.path("lt.pak")
+ self.path("lv.pak")
+ self.path("ml.pak")
+ self.path("mr.pak")
+ self.path("ms.pak")
+ self.path("nb.pak")
+ self.path("nl.pak")
+ self.path("pl.pak")
+ self.path("pt-BR.pak")
+ self.path("pt-PT.pak")
+ self.path("ro.pak")
+ self.path("ru.pak")
+ self.path("sk.pak")
+ self.path("sl.pak")
+ self.path("sr.pak")
+ self.path("sv.pak")
+ self.path("sw.pak")
+ self.path("ta.pak")
+ self.path("te.pak")
+ self.path("th.pak")
+ self.path("tr.pak")
+ self.path("uk.pak")
+ self.path("vi.pak")
+ self.path("zh-CN.pak")
+ self.path("zh-TW.pak")
+
+ with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')):
+ self.path("libvlc.dll")
+ self.path("libvlccore.dll")
+ self.path("plugins/")
+
+ # pull in the crash logger from other projects
# tag:"crash-logger" here as a cue to the exporter
self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'],
dst="win_crash_logger.exe")
@@ -768,7 +782,7 @@ class WindowsManifest(ViewerManifest):
substitution_strings['installer_file'] = installer_file
version_vars = """
- !define INSTEXE "SL_Launcher.exe"
+ !define INSTEXE "SLVersionChecker.exe"
!define VERSION "%(version_short)s"
!define VERSION_LONG "%(version)s"
!define VERSION_DASHES "%(version_dashes)s"
@@ -791,10 +805,10 @@ class WindowsManifest(ViewerManifest):
if(self.address_size == 64):
engage_registry="SetRegView 64"
- program_files="$PROGRAMFILES64"
+ program_files="!define MULTIUSER_USE_PROGRAMFILES64"
else:
engage_registry="SetRegView 32"
- program_files="$PROGRAMFILES32"
+ program_files=""
tempfile = "secondlife_setup_tmp.nsi"
# the following replaces strings in the nsi template
@@ -812,16 +826,15 @@ class WindowsManifest(ViewerManifest):
# note that the enclosing setup exe is signed later, after the makensis makes it.
# Unlike the viewer binary, the VMP filenames are invariant with respect to version, os, etc.
for exe in (
- "SL_Launcher.exe",
+ self.final_exe(),
+ "SLVersionChecker.exe",
):
self.sign(exe)
- # We use the Unicode version of NSIS, available from
- # http://www.scratchpaper.com/
# Check two paths, one for Program Files, and one for Program Files (x86).
# Yay 64bit windows.
for ProgramFiles in 'ProgramFiles', 'ProgramFiles(x86)':
- NSIS_path = os.path.expandvars(r'${%s}\NSIS\Unicode\makensis.exe' % ProgramFiles)
+ NSIS_path = os.path.expandvars(r'${%s}\NSIS\makensis.exe' % ProgramFiles)
if os.path.exists(NSIS_path):
break
installer_created=False
@@ -879,395 +892,327 @@ class DarwinManifest(ViewerManifest):
# darwin requires full app bundle packaging even for debugging.
return True
- def construct(self):
- # These are the names of the top-level application and the embedded
- # applications for the VMP and for the actual viewer, respectively.
- # These names, without the .app suffix, determine the flyover text for
- # their corresponding Dock icons.
- toplevel_app, toplevel_icon = "Second Life.app", "secondlife.icns"
- launcher_app, launcher_icon = "Second Life Launcher.app", "secondlife.icns"
- viewer_app, viewer_icon = "Second Life Viewer.app", "secondlife.icns"
+ def is_rearranging(self):
+ # That said, some stuff should still only be performed once.
+ # Are either of these actions in 'actions'? Is the set intersection
+ # non-empty?
+ return bool(set(["package", "unpacked"]).intersection(self.args['actions']))
+ def construct(self):
# copy over the build result (this is a no-op if run within the xcode script)
- self.path(os.path.join(self.args['configuration'], toplevel_app), dst="")
+ self.path(os.path.join(self.args['configuration'], self.channel()+".app"), dst="")
pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
relpkgdir = os.path.join(pkgdir, "lib", "release")
debpkgdir = os.path.join(pkgdir, "lib", "debug")
- # -------------------- top-level Second Life.app ---------------------
- # top-level Second Life application is only a container
with self.prefix(src="", dst="Contents"): # everything goes in Contents
- # top-level Info.plist is as generated by CMake
- Info_plist = "Info.plist"
- ## This self.path() call reports 0 files... skip?
- self.path(Info_plist)
- Info_plist = self.dst_path_of(Info_plist)
-
- # the one file in top-level MacOS directory is the trampoline to
- # our nested launcher_app
+ bugsplat_db = self.args.get('bugsplat')
+ if bugsplat_db:
+ # Inject BugsplatServerURL into Info.plist if provided.
+ Info_plist = self.dst_path_of("Info.plist")
+ Info = plistlib.readPlist(Info_plist)
+ # https://www.bugsplat.com/docs/platforms/os-x#configuration
+ Info["BugsplatServerURL"] = \
+ "https://{}.bugsplat.com/".format(bugsplat_db)
+ self.put_in_file(
+ plistlib.writePlistToString(Info),
+ os.path.basename(Info_plist),
+ "Info.plist")
+
+ # CEF framework goes inside Contents/Frameworks.
+ # Remember where we parked this car.
+ with self.prefix(src="", dst="Frameworks"):
+ CEF_framework = "Chromium Embedded Framework.framework"
+ self.path2basename(relpkgdir, CEF_framework)
+ CEF_framework = self.dst_path_of(CEF_framework)
+
+ if self.args.get('bugsplat'):
+ self.path2basename(relpkgdir, "BugsplatMac.framework")
+
with self.prefix(dst="MacOS"):
- toplevel_MacOS = self.get_dst_prefix()
- trampoline = self.put_in_file("""\
-#!/bin/bash
-open "%s" --args "$@"
-""" %
- # up one directory from MacOS to its sibling Resources directory
- os.path.join('$(dirname "$0")', os.pardir, 'Resources', launcher_app),
- "SL_Launcher", # write this file
- "trampoline") # flag to add to list of copied files
- # Script must be executable
- self.run_command(["chmod", "+x", trampoline])
-
- # Make a symlink to a nested app Frameworks directory that doesn't
- # yet exist. We shouldn't need this; the only things that need
- # Frameworks are nested apps under viewer_app, and they should
- # simply find its Contents/Frameworks by relative pathnames. But
- # empirically, we do: if we omit this symlink, CEF doesn't work --
- # the login splash screen doesn't even display. SIIIIGH.
- # We're passing a path that's already relative, hence symlinkf()
- # rather than relsymlinkf().
- self.symlinkf(os.path.join("Resources", viewer_app, "Contents", "Frameworks"))
-
- with self.prefix(src="", dst="Resources"):
- # top-level Resources directory should be pretty sparse
- # need .icns file referenced by top-level Info.plist
+ executable = self.dst_path_of(self.channel())
+ if self.args.get('bugsplat'):
+ # According to Apple Technical Note TN2206:
+ # https://developer.apple.com/library/archive/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG207
+ # "If an app uses @rpath or an absolute path to link to a
+ # dynamic library outside of the app, the app will be
+ # rejected by Gatekeeper. ... Neither the codesign nor the
+ # spctl tool will show the error."
+ # (Thanks, Apple. Maybe fix spctl to warn?)
+ # The BugsplatMac framework embeds @rpath, which is
+ # causing scary Gatekeeper popups at viewer start. Work
+ # around this by changing the reference baked into our
+ # viewer. The install_name_tool -change option needs the
+ # previous value. Instead of guessing -- which might
+ # silently be defeated by a BugSplat SDK update that
+ # changes their baked-in @rpath -- ask for the path
+ # stamped into the framework.
+ # Let exception, if any, propagate -- if this doesn't
+ # work, we need the build to noisily fail!
+ oldpath = subprocess.check_output(
+ ['objdump', '-macho', '-dylib-id', '-non-verbose',
+ os.path.join(relpkgdir, "BugsplatMac.framework", "BugsplatMac")]
+ ).splitlines()[-1] # take the last line of output
+ self.run_command(
+ ['install_name_tool', '-change', oldpath,
+ '@executable_path/../Frameworks/BugsplatMac.framework/BugsplatMac',
+ executable])
+
+ # NOTE: the -S argument to strip causes it to keep
+ # enough info for annotated backtraces (i.e. function
+ # names in the crash log). 'strip' with no arguments
+ # yields a slightly smaller binary but makes crash
+ # logs mostly useless. This may be desirable for the
+ # final release. Or not.
+ if ("package" in self.args['actions'] or
+ "unpacked" in self.args['actions']):
+ self.run_command(
+ ['strip', '-S', executable])
+
+ with self.prefix(dst="Resources"):
+ # defer cross-platform file copies until we're in the
+ # nested Resources directory
+ super(DarwinManifest, self).construct()
+
+ # need .icns file referenced by Info.plist
with self.prefix(src=self.icon_path(), dst="") :
- self.path(toplevel_icon)
-
- # ------------------- nested launcher_app --------------------
- with self.prefix(dst=os.path.join(launcher_app, "Contents")):
- # Info.plist is just like top-level one...
- Info = plistlib.readPlist(Info_plist)
- # except for these replacements:
- Info["CFBundleExecutable"] = "SL_Launcher"
- Info["CFBundleIconFile"] = launcher_icon
- self.put_in_file(
- plistlib.writePlistToString(Info),
- os.path.basename(Info_plist),
- "Info.plist")
-
- # copy VMP libs to MacOS
- with self.prefix(dst="MacOS"):
- #this copies over the python wrapper script,
- #associated utilities and required libraries, see
- #SL-321, SL-322, SL-323
- with self.prefix(src=os.path.join(pkgdir, "VMP"), dst=""):
- self.path("SL_Launcher")
- self.path("*.py")
- # certifi will be imported by requests; this is
- # our custom version to get our ca-bundle.crt
- self.path("certifi")
- with self.prefix(src=os.path.join(pkgdir, "lib", "python"), dst=""):
- # llbase provides our llrest service layer and llsd decoding
- with self.prefix("llbase"):
- # (Why is llbase treated specially here? What
- # DON'T we want to copy out of lib/python/llbase?)
- self.path("*.py")
- self.path("_cllsd.so")
- #requests module needed by llbase/llrest.py
- #this is only needed on POSIX, because in Windows
- #we compile it into the EXE
- for pypkg in "chardet", "idna", "requests", "urllib3":
- self.path(pypkg)
-
- # launcher_app/Contents/Resources
- with self.prefix(dst="Resources"):
- with self.prefix(src=self.icon_path(), dst="") :
- self.path(launcher_icon)
- with self.prefix(dst="vmp_icons"):
- self.path("secondlife.ico")
- #VMP Tkinter icons
- with self.prefix("vmp_icons"):
- self.path("*.png")
- self.path("*.gif")
-
- # -------------------- nested viewer_app ---------------------
- with self.prefix(dst=os.path.join(viewer_app, "Contents")):
- # Info.plist is just like top-level one...
- Info = plistlib.readPlist(Info_plist)
- # except for these replacements:
- # (CFBundleExecutable may be moot: SL_Launcher directly
- # runs the executable, instead of launching the app)
- Info["CFBundleExecutable"] = "Second Life"
- Info["CFBundleIconFile"] = viewer_icon
- self.put_in_file(
- plistlib.writePlistToString(Info),
- os.path.basename(Info_plist),
- "Info.plist")
-
- # CEF framework goes inside viewer_app/Contents/Frameworks.
- # Remember where we parked this car.
- with self.prefix(src="", dst="Frameworks"):
- CEF_framework = "Chromium Embedded Framework.framework"
- self.path2basename(relpkgdir, CEF_framework)
- CEF_framework = self.dst_path_of(CEF_framework)
-
- with self.prefix(dst="MacOS"):
- # CMake constructs the Second Life executable in the
- # MacOS directory belonging to the top-level Second
- # Life.app. Move it here.
- here = self.get_dst_prefix()
- relbase = os.path.realpath(os.path.dirname(Info_plist))
- self.cmakedirs(here)
- for f in os.listdir(toplevel_MacOS):
- if f == os.path.basename(trampoline):
- # don't move the trampoline script we just made!
- continue
- fromwhere = os.path.join(toplevel_MacOS, f)
- towhere = os.path.join(here, f)
- print "Moving %s => %s" % \
- (self.relpath(fromwhere, relbase),
- self.relpath(towhere, relbase))
- # now do it, only without relativizing paths
- os.rename(fromwhere, towhere)
-
- # NOTE: the -S argument to strip causes it to keep
- # enough info for annotated backtraces (i.e. function
- # names in the crash log). 'strip' with no arguments
- # yields a slightly smaller binary but makes crash
- # logs mostly useless. This may be desirable for the
- # final release. Or not.
- if ("package" in self.args['actions'] or
- "unpacked" in self.args['actions']):
- self.run_command(
- ['strip', '-S', self.dst_path_of('Second Life')])
-
- with self.prefix(dst="Resources"):
- # defer cross-platform file copies until we're in the right
- # nested Resources directory
- super(DarwinManifest, self).construct()
-
- with self.prefix(src=self.icon_path(), dst="") :
- self.path(viewer_icon)
-
- with self.prefix(src=relpkgdir, dst=""):
- self.path("libndofdev.dylib")
- self.path("libhunspell-1.3.0.dylib")
-
- with self.prefix("cursors_mac"):
- self.path("*.tif")
-
- self.path("licenses-mac.txt", dst="licenses.txt")
- self.path("featuretable_mac.txt")
- self.path("SecondLife.nib")
-
- with self.prefix(src=pkgdir,dst=""):
- self.path("ca-bundle.crt")
-
- self.path("SecondLife.nib")
-
- # Translations
- self.path("English.lproj/language.txt")
- self.replace_in(src="English.lproj/InfoPlist.strings",
- dst="English.lproj/InfoPlist.strings",
- searchdict={'%%VERSION%%':'.'.join(self.args['version'])}
- )
- self.path("German.lproj")
- self.path("Japanese.lproj")
- self.path("Korean.lproj")
- self.path("da.lproj")
- self.path("es.lproj")
- self.path("fr.lproj")
- self.path("hu.lproj")
- self.path("it.lproj")
- self.path("nl.lproj")
- self.path("pl.lproj")
- self.path("pt.lproj")
- self.path("ru.lproj")
- self.path("tr.lproj")
- self.path("uk.lproj")
- self.path("zh-Hans.lproj")
-
- def path_optional(src, dst):
- """
- For a number of our self.path() calls, not only do we want
- to deal with the absence of src, we also want to remember
- which were present. Return either an empty list (absent)
- or a list containing dst (present). Concatenate these
- return values to get a list of all libs that are present.
- """
- # This was simple before we started needing to pass
- # wildcards. Fortunately, self.path() ends up appending a
- # (source, dest) pair to self.file_list for every expanded
- # file processed. Remember its size before the call.
- oldlen = len(self.file_list)
- self.path(src, dst)
- # The dest appended to self.file_list has been prepended
- # with self.get_dst_prefix(). Strip it off again.
- added = [os.path.relpath(d, self.get_dst_prefix())
- for s, d in self.file_list[oldlen:]]
- if not added:
- print "Skipping %s" % dst
- return added
-
- # dylibs is a list of all the .dylib files we expect to need
- # in our bundled sub-apps. For each of these we'll create a
- # symlink from sub-app/Contents/Resources to the real .dylib.
- # Need to get the llcommon dll from any of the build directories as well.
- libfile_parent = self.get_dst_prefix()
- libfile = "libllcommon.dylib"
- dylibs = path_optional(self.find_existing_file(os.path.join(os.pardir,
- "llcommon",
- self.args['configuration'],
- libfile),
- os.path.join(relpkgdir, libfile)),
- dst=libfile)
-
- for libfile in (
- "libapr-1.0.dylib",
- "libaprutil-1.0.dylib",
- "libcollada14dom.dylib",
- "libexpat.1.dylib",
- "libexception_handler.dylib",
- "libGLOD.dylib",
- # libnghttp2.dylib is a symlink to
- # libnghttp2.major.dylib, which is a symlink to
- # libnghttp2.version.dylib. Get all of them.
- "libnghttp2.*dylib",
- ):
- dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
-
- # SLVoice and vivox lols, no symlinks needed
- for libfile in (
- 'libortp.dylib',
- 'libsndfile.dylib',
- 'libvivoxoal.dylib',
- 'libvivoxsdk.dylib',
- 'libvivoxplatform.dylib',
- 'SLVoice',
- ):
- self.path2basename(relpkgdir, libfile)
-
- # dylibs that vary based on configuration
- if self.args['configuration'].lower() == 'debug':
- for libfile in (
- "libfmodexL.dylib",
- ):
- dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile)
- else:
- for libfile in (
- "libfmodex.dylib",
- ):
- dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
-
- # our apps
- executable_path = {}
- for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"),
- # plugin launcher
- (os.path.join("llplugin", "slplugin"), "SLPlugin.app"),
- ):
- self.path2basename(os.path.join(os.pardir,
- app_bld_dir, self.args['configuration']),
- app)
- executable_path[app] = \
- self.dst_path_of(os.path.join(app, "Contents", "MacOS"))
-
- # our apps dependencies on shared libs
- # for each app, for each dylib we collected in dylibs,
- # create a symlink to the real copy of the dylib.
- with self.prefix(dst=os.path.join(app, "Contents", "Resources")):
- for libfile in dylibs:
- self.relsymlinkf(os.path.join(libfile_parent, libfile))
-
- # Dullahan helper apps go inside SLPlugin.app
- with self.prefix(dst=os.path.join(
- "SLPlugin.app", "Contents", "Frameworks")):
-
- frameworkname = 'Chromium Embedded Framework'
-
- # This code constructs a relative symlink from the
- # target framework folder back to the real CEF framework.
- # It needs to be relative so that the symlink still works when
- # (as is normal) the user moves the app bundle out of the DMG
- # and into the /Applications folder. Note we pass catch=False,
- # letting the uncaught exception terminate the process, since
- # without this symlink, Second Life web media can't possibly work.
-
- # It might seem simpler just to symlink Frameworks back to
- # the parent of Chromimum Embedded Framework.framework. But
- # that would create a symlink cycle, which breaks our
- # packaging step. So make a symlink from Chromium Embedded
- # Framework.framework to the directory of the same name, which
- # is NOT an ancestor of the symlink.
-
- # from SLPlugin.app/Contents/Frameworks/Chromium Embedded
- # Framework.framework back to
- # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework
- SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False)
-
- # copy DullahanHelper.app
- self.path2basename(relpkgdir, 'DullahanHelper.app')
-
- # and fix that up with a Frameworks/CEF symlink too
- with self.prefix(dst=os.path.join(
- 'DullahanHelper.app', 'Contents', 'Frameworks')):
- # from Dullahan Helper.app/Contents/Frameworks/Chromium Embedded
- # Framework.framework back to
- # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework
- # Since SLPlugin_framework is itself a
- # symlink, don't let relsymlinkf() resolve --
- # explicitly call relpath(symlink=True) and
- # create that symlink here.
- DullahanHelper_framework = \
- self.symlinkf(self.relpath(SLPlugin_framework, symlink=True),
- catch=False)
-
- # change_command includes install_name_tool, the
- # -change subcommand and the old framework rpath
- # stamped into the executable. To use it with
- # run_command(), we must still append the new
- # framework path and the pathname of the
- # executable to change.
- change_command = [
- 'install_name_tool', '-change',
- '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework']
-
- with self.prefix(dst=os.path.join(
- 'DullahanHelper.app', 'Contents', 'MacOS')):
- # Now self.get_dst_prefix() is, at runtime,
- # @executable_path. Locate the helper app
- # framework (which is a symlink) from here.
- newpath = os.path.join(
- '@executable_path',
- self.relpath(DullahanHelper_framework, symlink=True),
- frameworkname)
- # and restamp the DullahanHelper executable
- self.run_command(
- change_command +
- [newpath, self.dst_path_of('DullahanHelper')])
-
- # SLPlugin plugins
- with self.prefix(dst="llplugin"):
- dylibexecutable = 'media_plugin_cef.dylib'
- self.path2basename("../media_plugins/cef/" + self.args['configuration'],
- dylibexecutable)
-
- # Do this install_name_tool *after* media plugin is copied over.
- # Locate the framework lib executable -- relative to
- # SLPlugin.app/Contents/MacOS, which will be our
- # @executable_path at runtime!
- newpath = os.path.join(
- '@executable_path',
- self.relpath(SLPlugin_framework, executable_path["SLPlugin.app"],
- symlink=True),
- frameworkname)
- # restamp media_plugin_cef.dylib
- self.run_command(
- change_command +
- [newpath, self.dst_path_of(dylibexecutable)])
+ self.path("secondlife.icns")
+
+ # Copy in the updater script and helper modules
+ self.path(src=os.path.join(pkgdir, 'VMP'), dst="updater")
+
+ with self.prefix(src="", dst=os.path.join("updater", "icons")):
+ self.path2basename(self.icon_path(), "secondlife.ico")
+ with self.prefix(src="vmp_icons", dst=""):
+ self.path("*.png")
+ self.path("*.gif")
- # copy LibVLC plugin itself
- self.path2basename("../media_plugins/libvlc/" + self.args['configuration'],
- "media_plugin_libvlc.dylib")
+ with self.prefix(src=relpkgdir, dst=""):
+ self.path("libndofdev.dylib")
+ self.path("libhunspell-1.3.0.dylib")
- # copy LibVLC dynamic libraries
- with self.prefix(src=relpkgdir, dst="lib"):
- self.path( "libvlc*.dylib*" )
- # copy LibVLC plugins folder
- with self.prefix(src='plugins', dst=""):
- self.path( "*.dylib" )
- self.path( "plugins.dat" )
+ with self.prefix(src_dst="cursors_mac"):
+ self.path("*.tif")
+
+ self.path("licenses-mac.txt", dst="licenses.txt")
+ self.path("featuretable_mac.txt")
+ self.path("SecondLife.nib")
+
+ with self.prefix(src=pkgdir,dst=""):
+ self.path("ca-bundle.crt")
+
+ # Translations
+ self.path("English.lproj/language.txt")
+ self.replace_in(src="English.lproj/InfoPlist.strings",
+ dst="English.lproj/InfoPlist.strings",
+ searchdict={'%%VERSION%%':'.'.join(self.args['version'])}
+ )
+ self.path("German.lproj")
+ self.path("Japanese.lproj")
+ self.path("Korean.lproj")
+ self.path("da.lproj")
+ self.path("es.lproj")
+ self.path("fr.lproj")
+ self.path("hu.lproj")
+ self.path("it.lproj")
+ self.path("nl.lproj")
+ self.path("pl.lproj")
+ self.path("pt.lproj")
+ self.path("ru.lproj")
+ self.path("tr.lproj")
+ self.path("uk.lproj")
+ self.path("zh-Hans.lproj")
+
+ def path_optional(src, dst):
+ """
+ For a number of our self.path() calls, not only do we want
+ to deal with the absence of src, we also want to remember
+ which were present. Return either an empty list (absent)
+ or a list containing dst (present). Concatenate these
+ return values to get a list of all libs that are present.
+ """
+ # This was simple before we started needing to pass
+ # wildcards. Fortunately, self.path() ends up appending a
+ # (source, dest) pair to self.file_list for every expanded
+ # file processed. Remember its size before the call.
+ oldlen = len(self.file_list)
+ self.path(src, dst)
+ # The dest appended to self.file_list has been prepended
+ # with self.get_dst_prefix(). Strip it off again.
+ added = [os.path.relpath(d, self.get_dst_prefix())
+ for s, d in self.file_list[oldlen:]]
+ if not added:
+ print "Skipping %s" % dst
+ return added
+
+ # dylibs is a list of all the .dylib files we expect to need
+ # in our bundled sub-apps. For each of these we'll create a
+ # symlink from sub-app/Contents/Resources to the real .dylib.
+ # Need to get the llcommon dll from any of the build directories as well.
+ libfile_parent = self.get_dst_prefix()
+ libfile = "libllcommon.dylib"
+ dylibs = path_optional(self.find_existing_file(os.path.join(os.pardir,
+ "llcommon",
+ self.args['configuration'],
+ libfile),
+ os.path.join(relpkgdir, libfile)),
+ dst=libfile)
+
+ for libfile in (
+ "libapr-1.0.dylib",
+ "libaprutil-1.0.dylib",
+ "libcollada14dom.dylib",
+ "libexpat.1.dylib",
+ "libexception_handler.dylib",
+ "libGLOD.dylib",
+ # libnghttp2.dylib is a symlink to
+ # libnghttp2.major.dylib, which is a symlink to
+ # libnghttp2.version.dylib. Get all of them.
+ "libnghttp2.*dylib",
+ ):
+ dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
+
+ # SLVoice and vivox lols, no symlinks needed
+ for libfile in (
+ 'libortp.dylib',
+ 'libsndfile.dylib',
+ 'libvivoxoal.dylib',
+ 'libvivoxsdk.dylib',
+ 'libvivoxplatform.dylib',
+ 'SLVoice',
+ ):
+ self.path2basename(relpkgdir, libfile)
+
+ # dylibs that vary based on configuration
+ if self.args['configuration'].lower() == 'debug':
+ for libfile in (
+ "libfmodexL.dylib",
+ ):
+ dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile)
+ else:
+ for libfile in (
+ "libfmodex.dylib",
+ ):
+ dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
+
+ # our apps
+ executable_path = {}
+ for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"),
+ # plugin launcher
+ (os.path.join("llplugin", "slplugin"), "SLPlugin.app"),
+ ):
+ self.path2basename(os.path.join(os.pardir,
+ app_bld_dir, self.args['configuration']),
+ app)
+ executable_path[app] = \
+ self.dst_path_of(os.path.join(app, "Contents", "MacOS"))
+
+ # our apps dependencies on shared libs
+ # for each app, for each dylib we collected in dylibs,
+ # create a symlink to the real copy of the dylib.
+ with self.prefix(dst=os.path.join(app, "Contents", "Resources")):
+ for libfile in dylibs:
+ self.relsymlinkf(os.path.join(libfile_parent, libfile))
+
+ # Dullahan helper apps go inside SLPlugin.app
+ with self.prefix(dst=os.path.join(
+ "SLPlugin.app", "Contents", "Frameworks")):
+
+ frameworkname = 'Chromium Embedded Framework'
+
+ # This code constructs a relative symlink from the
+ # target framework folder back to the real CEF framework.
+ # It needs to be relative so that the symlink still works when
+ # (as is normal) the user moves the app bundle out of the DMG
+ # and into the /Applications folder. Note we pass catch=False,
+ # letting the uncaught exception terminate the process, since
+ # without this symlink, Second Life web media can't possibly work.
+
+ # It might seem simpler just to symlink Frameworks back to
+ # the parent of Chromimum Embedded Framework.framework. But
+ # that would create a symlink cycle, which breaks our
+ # packaging step. So make a symlink from Chromium Embedded
+ # Framework.framework to the directory of the same name, which
+ # is NOT an ancestor of the symlink.
+
+ # from SLPlugin.app/Contents/Frameworks/Chromium Embedded
+ # Framework.framework back to
+ # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework
+ SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False)
+
+ # copy DullahanHelper.app
+ self.path2basename(relpkgdir, 'DullahanHelper.app')
+
+ # and fix that up with a Frameworks/CEF symlink too
+ with self.prefix(dst=os.path.join(
+ 'DullahanHelper.app', 'Contents', 'Frameworks')):
+ # from Dullahan Helper.app/Contents/Frameworks/Chromium Embedded
+ # Framework.framework back to
+ # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework
+ # Since SLPlugin_framework is itself a
+ # symlink, don't let relsymlinkf() resolve --
+ # explicitly call relpath(symlink=True) and
+ # create that symlink here.
+ DullahanHelper_framework = \
+ self.symlinkf(self.relpath(SLPlugin_framework, symlink=True),
+ catch=False)
+
+ # change_command includes install_name_tool, the
+ # -change subcommand and the old framework rpath
+ # stamped into the executable. To use it with
+ # run_command(), we must still append the new
+ # framework path and the pathname of the
+ # executable to change.
+ change_command = [
+ 'install_name_tool', '-change',
+ '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework']
+
+ with self.prefix(dst=os.path.join(
+ 'DullahanHelper.app', 'Contents', 'MacOS')):
+ # Now self.get_dst_prefix() is, at runtime,
+ # @executable_path. Locate the helper app
+ # framework (which is a symlink) from here.
+ newpath = os.path.join(
+ '@executable_path',
+ self.relpath(DullahanHelper_framework, symlink=True),
+ frameworkname)
+ # and restamp the DullahanHelper executable
+ self.run_command(
+ change_command +
+ [newpath, self.dst_path_of('DullahanHelper')])
+
+ # SLPlugin plugins
+ with self.prefix(dst="llplugin"):
+ dylibexecutable = 'media_plugin_cef.dylib'
+ self.path2basename("../media_plugins/cef/" + self.args['configuration'],
+ dylibexecutable)
+
+ # Do this install_name_tool *after* media plugin is copied over.
+ # Locate the framework lib executable -- relative to
+ # SLPlugin.app/Contents/MacOS, which will be our
+ # @executable_path at runtime!
+ newpath = os.path.join(
+ '@executable_path',
+ self.relpath(SLPlugin_framework, executable_path["SLPlugin.app"],
+ symlink=True),
+ frameworkname)
+ # restamp media_plugin_cef.dylib
+ self.run_command(
+ change_command +
+ [newpath, self.dst_path_of(dylibexecutable)])
+
+ # copy LibVLC plugin itself
+ self.path2basename("../media_plugins/libvlc/" + self.args['configuration'],
+ "media_plugin_libvlc.dylib")
+
+ # copy LibVLC dynamic libraries
+ with self.prefix(src=relpkgdir, dst="lib"):
+ self.path( "libvlc*.dylib*" )
+ # copy LibVLC plugins folder
+ with self.prefix(src='plugins', dst=""):
+ self.path( "*.dylib" )
+ self.path( "plugins.dat" )
def package_finish(self):
global CHANNEL_VENDOR_BASE
@@ -1416,10 +1361,7 @@ open "%s" --args "$@"
else:
print >> sys.stderr, "Maximum codesign attempts exceeded; giving up"
raise
- self.run_command(['spctl', '-a', '-texec', '-vv', app_in_dmg])
-
- imagename="SecondLife_" + '_'.join(self.args['version'])
-
+ self.run_command(['spctl', '-a', '-texec', '-vvvv', app_in_dmg])
finally:
# Unmount the image even if exceptions from any of the above
@@ -1458,29 +1400,25 @@ class LinuxManifest(ViewerManifest):
debpkgdir = os.path.join(pkgdir, "lib", "debug")
self.path("licenses-linux.txt","licenses.txt")
- with self.prefix("linux_tools", dst=""):
+ with self.prefix("linux_tools"):
self.path("client-readme.txt","README-linux.txt")
self.path("client-readme-voice.txt","README-linux-voice.txt")
self.path("client-readme-joystick.txt","README-linux-joystick.txt")
self.path("wrapper.sh","secondlife")
- with self.prefix(src="", dst="etc"):
+ with self.prefix(dst="etc"):
self.path("handle_secondlifeprotocol.sh")
self.path("register_secondlifeprotocol.sh")
self.path("refresh_desktop_app_entry.sh")
self.path("launch_url.sh")
self.path("install.sh")
- with self.prefix(src="", dst="bin"):
+ with self.prefix(dst="bin"):
self.path("secondlife-bin","do-not-directly-run-secondlife-bin")
self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin")
self.path2basename("../llplugin/slplugin", "SLPlugin")
#this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323
with self.prefix(src="../viewer_components/manager", dst=""):
- self.path("SL_Launcher")
self.path("*.py")
- with self.prefix(src=os.path.join("lib", "python", "llbase"), dst="llbase"):
- self.path("*.py")
- self.path("_cllsd.so")
# recurses, packaged again
self.path("res-sdl")
@@ -1488,9 +1426,9 @@ class LinuxManifest(ViewerManifest):
# Get the icons based on the channel type
icon_path = self.icon_path()
print "DEBUG: icon_path '%s'" % icon_path
- with self.prefix(src=icon_path, dst="") :
+ with self.prefix(src=icon_path) :
self.path("secondlife_256.png","secondlife_icon.png")
- with self.prefix(src="",dst="res-sdl") :
+ with self.prefix(dst="res-sdl") :
self.path("secondlife_256.BMP","ll_icon.BMP")
# plugins
@@ -1512,7 +1450,7 @@ class LinuxManifest(ViewerManifest):
self.path("featuretable_linux.txt")
- with self.prefix(src=pkgdir,dst=""):
+ with self.prefix(src=pkgdir):
self.path("ca-bundle.crt")
def package_finish(self):
@@ -1555,7 +1493,7 @@ class LinuxManifest(ViewerManifest):
self.run_command(
["find"] +
[os.path.join(self.get_dst_prefix(), dir) for dir in ('bin', 'lib')] +
- ['-type', 'f', '!', '-name', '*.py', '!', '-name', 'SL_Launcher',
+ ['-type', 'f', '!', '-name', '*.py',
'!', '-name', 'update_install', '-exec', 'strip', '-S', '{}', ';'])
class Linux_i686_Manifest(LinuxManifest):
@@ -1568,7 +1506,7 @@ class Linux_i686_Manifest(LinuxManifest):
relpkgdir = os.path.join(pkgdir, "lib", "release")
debpkgdir = os.path.join(pkgdir, "lib", "debug")
- with self.prefix(relpkgdir, dst="lib"):
+ with self.prefix(src=relpkgdir, dst="lib"):
self.path("libapr-1.so")
self.path("libapr-1.so.0")
self.path("libapr-1.so.0.4.5")
@@ -1654,4 +1592,8 @@ class Linux_x86_64_Manifest(LinuxManifest):
################################################################
if __name__ == "__main__":
- main()
+ extra_arguments = [
+ dict(name='bugsplat', description="""BugSplat database to which to post crashes,
+ if BugSplat crash reporting is desired""", default=''),
+ ]
+ main(extra=extra_arguments)
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index bdeaeec970..861ec1d942 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -534,7 +534,6 @@ int main(int argc, char **argv)
LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
}
LLError::setFatalFunction(wouldHaveCrashed);
- LLError::setPrintLocation(true);
std::string test_app_name(argv[0]);
std::string test_log = test_app_name + ".log";
LLFile::remove(test_log);
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index c767d52c7b..9193d32b49 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -128,6 +128,15 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL;
}
+namespace {
+// Instantiate this rendezvous point at namespace scope so it's already
+// present no matter how early the updater might post to it.
+// Use an LLEventMailDrop, which has future-like semantics: regardless of the
+// relative order in which post() or listen() are called, it delivers each
+// post() event to its listener(s) until one of them consumes that event.
+static LLEventMailDrop sSyncPoint("LoginSync");
+}
+
void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
{
LLSD printable_params = login_params;
@@ -219,7 +228,44 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
}
else
{
- sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
+ // Synchronize here with the updater. We synchronize here rather
+ // than in the fail.login handler, which actually examines the
+ // response from login.cgi, because here we are definitely in a
+ // coroutine and can definitely use suspendUntilBlah(). Whoever's
+ // listening for fail.login might not be.
+
+ // If the reason for login failure is that we must install a
+ // required update, we definitely want to pass control to the
+ // updater to manage that for us. We'll handle any other login
+ // failure ourselves, as usual. We figure that no matter where you
+ // are in the world, or what kind of network you're on, we can
+ // reasonably expect the Viewer Version Manager to respond more or
+ // less as quickly as login.cgi. This synchronization is only
+ // intended to smooth out minor races between the two services.
+ // But what if the updater crashes? Use a timeout so that
+ // eventually we'll tire of waiting for it and carry on as usual.
+ // Given the above, it can be a fairly short timeout, at least
+ // from a human point of view.
+
+ // Since sSyncPoint is an LLEventMailDrop, we DEFINITELY want to
+ // consume the posted event.
+ LLCoros::OverrideConsuming oc(true);
+ // Timeout should produce the isUndefined() object passed here.
+ LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
+ LLSD updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD());
+ if (updater.isUndefined())
+ {
+ LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login"
+ << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL;
+ }
+ // Let the fail.login handler deal with empty updater response.
+ LLSD responses(mAuthResponse["responses"]);
+ responses["updater"] = updater;
+ sendProgressEvent("offline", "fail.login", responses);
}
return; // Done!
}
@@ -249,10 +295,10 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
// *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an
// llsd with no "responses" node. To make the output from an incomplete login symmetrical
// to success, add a data/message and data/reason fields.
- LLSD error_response;
- error_response["reason"] = mAuthResponse["status"];
- error_response["errorcode"] = mAuthResponse["errorcode"];
- error_response["message"] = mAuthResponse["error"];
+ LLSD error_response(LLSDMap
+ ("reason", mAuthResponse["status"])
+ ("errorcode", mAuthResponse["errorcode"])
+ ("message", mAuthResponse["error"]));
if(mAuthResponse.has("certificate"))
{
error_response["certificate"] = mAuthResponse["certificate"];
diff --git a/indra/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt
index 144d037a31..4fba26ab2f 100644
--- a/indra/win_crash_logger/CMakeLists.txt
+++ b/indra/win_crash_logger/CMakeLists.txt
@@ -89,7 +89,6 @@ target_link_libraries(windows-crash-logger
${GOOGLE_PERFTOOLS_LIBRARIES}
user32
gdi32
- ole32
oleaut32
wininet
Wldap32