# Conflicts:
#	indra/llimage/llimagebmp.cpp
#	indra/llimage/llimagetga.cpp
#	indra/llrender/llrender.cpp
#	indra/llui/lltransutil.cpp
#	indra/newview/llappviewer.cpp
#	indra/newview/llviewerwindow.cpp
master
Ansariel 2024-03-26 22:43:42 +01:00
commit 1f75fbd3b5
29 changed files with 242 additions and 60 deletions

View File

@ -24,6 +24,8 @@ jobs:
outputs: outputs:
viewer_channel: ${{ steps.build.outputs.viewer_channel }} viewer_channel: ${{ steps.build.outputs.viewer_channel }}
viewer_version: ${{ steps.build.outputs.viewer_version }} viewer_version: ${{ steps.build.outputs.viewer_version }}
viewer_branch: ${{ steps.which-branch.outputs.branch }}
relnotes: ${{ steps.which-branch.outputs.relnotes }}
imagename: ${{ steps.build.outputs.imagename }} imagename: ${{ steps.build.outputs.imagename }}
env: env:
AUTOBUILD_ADDRSIZE: 64 AUTOBUILD_ADDRSIZE: 64
@ -40,8 +42,6 @@ jobs:
DEVELOPER_DIR: ${{ matrix.developer_dir }} DEVELOPER_DIR: ${{ matrix.developer_dir }}
# Ensure that Linden viewer builds engage Bugsplat. # Ensure that Linden viewer builds engage Bugsplat.
BUGSPLAT_DB: ${{ matrix.configuration != 'ReleaseOS' && 'SecondLife_Viewer_2018' || '' }} BUGSPLAT_DB: ${{ matrix.configuration != 'ReleaseOS' && 'SecondLife_Viewer_2018' || '' }}
BUGSPLAT_PASS: ${{ secrets.BUGSPLAT_PASS }}
BUGSPLAT_USER: ${{ secrets.BUGSPLAT_USER }}
build_coverity: false build_coverity: false
build_log_dir: ${{ github.workspace }}/.logs build_log_dir: ${{ github.workspace }}/.logs
build_viewer: true build_viewer: true
@ -65,7 +65,7 @@ jobs:
ref: ${{ github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Setup python - name: Setup python
uses: actions/setup-python@v4 uses: actions/setup-python@v5
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
@ -86,7 +86,7 @@ jobs:
run: pip3 install autobuild llsd run: pip3 install autobuild llsd
- name: Cache autobuild packages - name: Cache autobuild packages
uses: actions/cache@v3 uses: actions/cache@v4
id: cache-installables id: cache-installables
with: with:
path: .autobuild-installables path: .autobuild-installables
@ -260,23 +260,36 @@ jobs:
${{ steps.build.outputs.physicstpv }} ${{ steps.build.outputs.physicstpv }}
sign-and-package-windows: sign-and-package-windows:
env:
AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }}
AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
needs: build needs: build
runs-on: windows runs-on: windows
steps: steps:
- name: Sign and package Windows viewer - name: Sign and package Windows viewer
if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID
uses: secondlife/viewer-build-util/sign-pkg-windows@v1 uses: secondlife/viewer-build-util/sign-pkg-windows@v1
with: with:
vault_uri: "${{ secrets.AZURE_KEY_VAULT_URI }}" vault_uri: "${{ env.AZURE_KEY_VAULT_URI }}"
cert_name: "${{ secrets.AZURE_CERT_NAME }}" cert_name: "${{ env.AZURE_CERT_NAME }}"
client_id: "${{ secrets.AZURE_CLIENT_ID }}" client_id: "${{ env.AZURE_CLIENT_ID }}"
client_secret: "${{ secrets.AZURE_CLIENT_SECRET }}" client_secret: "${{ env.AZURE_CLIENT_SECRET }}"
tenant_id: "${{ secrets.AZURE_TENANT_ID }}" tenant_id: "${{ env.AZURE_TENANT_ID }}"
sign-and-package-mac: sign-and-package-mac:
env:
NOTARIZE_CREDS_MACOS: ${{ secrets.NOTARIZE_CREDS_MACOS }}
SIGNING_CERT_MACOS: ${{ secrets.SIGNING_CERT_MACOS }}
SIGNING_CERT_MACOS_IDENTITY: ${{ secrets.SIGNING_CERT_MACOS_IDENTITY }}
SIGNING_CERT_MACOS_PASSWORD: ${{ secrets.SIGNING_CERT_MACOS_PASSWORD }}
needs: build needs: build
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- name: Unpack Mac notarization credentials - name: Unpack Mac notarization credentials
if: env.NOTARIZE_CREDS_MACOS
id: note-creds id: note-creds
shell: bash shell: bash
run: | run: |
@ -284,7 +297,7 @@ jobs:
# USERNAME="..." # USERNAME="..."
# PASSWORD="..." # PASSWORD="..."
# TEAM_ID="..." # TEAM_ID="..."
eval "${{ secrets.NOTARIZE_CREDS_MACOS }}" eval "${{ env.NOTARIZE_CREDS_MACOS }}"
echo "::add-mask::$USERNAME" echo "::add-mask::$USERNAME"
echo "::add-mask::$PASSWORD" echo "::add-mask::$PASSWORD"
echo "::add-mask::$TEAM_ID" echo "::add-mask::$TEAM_ID"
@ -296,45 +309,54 @@ jobs:
[[ -n "$USERNAME" && -n "$PASSWORD" && -n "$TEAM_ID" ]] [[ -n "$USERNAME" && -n "$PASSWORD" && -n "$TEAM_ID" ]]
- name: Sign and package Mac viewer - name: Sign and package Mac viewer
if: env.SIGNING_CERT_MACOS && env.SIGNING_CERT_MACOS_IDENTITY && env.SIGNING_CERT_MACOS_PASSWORD && steps.note-creds.outputs.note_user && steps.note-creds.outputs.note_pass && steps.note-creds.outputs.note_team
uses: secondlife/viewer-build-util/sign-pkg-mac@v1 uses: secondlife/viewer-build-util/sign-pkg-mac@v1
with: with:
channel: ${{ needs.build.outputs.viewer_channel }} channel: ${{ needs.build.outputs.viewer_channel }}
imagename: ${{ needs.build.outputs.imagename }} imagename: ${{ needs.build.outputs.imagename }}
cert_base64: ${{ secrets.SIGNING_CERT_MACOS }} cert_base64: ${{ env.SIGNING_CERT_MACOS }}
cert_name: ${{ secrets.SIGNING_CERT_MACOS_IDENTITY }} cert_name: ${{ env.SIGNING_CERT_MACOS_IDENTITY }}
cert_pass: ${{ secrets.SIGNING_CERT_MACOS_PASSWORD }} cert_pass: ${{ env.SIGNING_CERT_MACOS_PASSWORD }}
note_user: ${{ steps.note-creds.outputs.note_user }} note_user: ${{ steps.note-creds.outputs.note_user }}
note_pass: ${{ steps.note-creds.outputs.note_pass }} note_pass: ${{ steps.note-creds.outputs.note_pass }}
note_team: ${{ steps.note-creds.outputs.note_team }} note_team: ${{ steps.note-creds.outputs.note_team }}
post-windows-symbols: post-windows-symbols:
env:
BUGSPLAT_USER: ${{ secrets.BUGSPLAT_USER }}
BUGSPLAT_PASS: ${{ secrets.BUGSPLAT_PASS }}
needs: build needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Post Windows symbols - name: Post Windows symbols
if: env.BUGSPLAT_USER && env.BUGSPLAT_PASS
uses: secondlife/viewer-build-util/post-bugsplat-windows@v1 uses: secondlife/viewer-build-util/post-bugsplat-windows@v1
with: with:
username: ${{ secrets.BUGSPLAT_USER }} username: ${{ env.BUGSPLAT_USER }}
password: ${{ secrets.BUGSPLAT_PASS }} password: ${{ env.BUGSPLAT_PASS }}
database: "SecondLife_Viewer_2018" database: "SecondLife_Viewer_2018"
channel: ${{ needs.build.outputs.viewer_channel }} channel: ${{ needs.build.outputs.viewer_channel }}
version: ${{ needs.build.outputs.viewer_version }} version: ${{ needs.build.outputs.viewer_version }}
post-mac-symbols: post-mac-symbols:
env:
BUGSPLAT_USER: ${{ secrets.BUGSPLAT_USER }}
BUGSPLAT_PASS: ${{ secrets.BUGSPLAT_PASS }}
needs: build needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Post Mac symbols - name: Post Mac symbols
if: env.BUGSPLAT_USER && env.BUGSPLAT_PASS
uses: secondlife/viewer-build-util/post-bugsplat-mac@v1 uses: secondlife/viewer-build-util/post-bugsplat-mac@v1
with: with:
username: ${{ secrets.BUGSPLAT_USER }} username: ${{ env.BUGSPLAT_USER }}
password: ${{ secrets.BUGSPLAT_PASS }} password: ${{ env.BUGSPLAT_PASS }}
database: "SecondLife_Viewer_2018" database: "SecondLife_Viewer_2018"
channel: ${{ needs.build.outputs.viewer_channel }} channel: ${{ needs.build.outputs.viewer_channel }}
version: ${{ needs.build.outputs.viewer_version }} version: ${{ needs.build.outputs.viewer_version }}
release: release:
needs: [sign-and-package-windows, sign-and-package-mac] needs: [build, sign-and-package-windows, sign-and-package-mac]
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life_') if: github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life_')
steps: steps:
@ -365,17 +387,31 @@ jobs:
mv newview/viewer_version.txt macOS-viewer_version.txt mv newview/viewer_version.txt macOS-viewer_version.txt
# forked from softprops/action-gh-release # forked from softprops/action-gh-release
- uses: secondlife-3p/action-gh-release@v1 - name: Create GitHub release
id: release
uses: secondlife-3p/action-gh-release@v1
with: with:
# name the release page for the build number so we can find it # name the release page for the branch
# easily (analogous to looking up a codeticket build page) name: "${{ needs.build.outputs.viewer_branch }}"
name: "v${{ github.run_id }}" # SL-20546: want the channel and version to be visible on the
# release page
body: |
Build ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
${{ needs.build.outputs.viewer_channel }}
${{ needs.build.outputs.viewer_version }}
${{ needs.build.outputs.relnotes }}
prerelease: true prerelease: true
generate_release_notes: true generate_release_notes: true
# the only reason we generate a GH release is to post build products target_commitish: ${{ github.sha }}
previous_tag: release
append_body: true
fail_on_unmatched_files: true fail_on_unmatched_files: true
files: | files: |
*.dmg *.dmg
*.exe *.exe
*-autobuild-package.xml *-autobuild-package.xml
*-viewer_version.txt *-viewer_version.txt
- name: post release URL
run: |
echo "::notice::Release ${{ steps.release.outputs.url }}"

View File

@ -18,6 +18,7 @@ jobs:
stale-pr-message: This pull request is stale because it has been open 30 days with no activity. Remove stale label or comment or it will be closed in 7 days stale-pr-message: This pull request is stale because it has been open 30 days with no activity. Remove stale label or comment or it will be closed in 7 days
days-before-stale: 30 days-before-stale: 30
days-before-close: 7 days-before-close: 7
days-before-issue-close: -1
exempt-pr-labels: blocked,must,should,keep exempt-pr-labels: blocked,must,should,keep
stale-pr-label: stale stale-pr-label: stale
- name: Print outputs - name: Print outputs

View File

@ -175,28 +175,6 @@ pre_build()
VIEWER_SYMBOL_FILE="$(native_path "$abs_build_dir/newview/$variant/secondlife-symbols-$symplat-${AUTOBUILD_ADDRSIZE}.tar.bz2")" VIEWER_SYMBOL_FILE="$(native_path "$abs_build_dir/newview/$variant/secondlife-symbols-$symplat-${AUTOBUILD_ADDRSIZE}.tar.bz2")"
fi fi
# expect these variables to be set in the environment from GitHub secrets
if [[ -n "$BUGSPLAT_DB" ]]
then
# don't spew credentials into build log
set +x
if [[ -z "$BUGSPLAT_USER" || -z "$BUGSPLAT_PASS" ]]
then
# older mechanism involving build-secrets repo -
# if build_secrets_checkout isn't set, report its name
bugsplat_sh="${build_secrets_checkout:-\$build_secrets_checkout}/bugsplat/bugsplat.sh"
if [ -r "$bugsplat_sh" ]
then # show that we're doing this, just not the contents
echo source "$bugsplat_sh"
source "$bugsplat_sh"
else
fatal "BUGSPLAT_USER or BUGSPLAT_PASS missing, and no $bugsplat_sh"
fi
fi
set -x
export BUGSPLAT_USER BUGSPLAT_PASS
fi
# honor autobuild_configure_parameters same as sling-buildscripts # honor autobuild_configure_parameters same as sling-buildscripts
eval_autobuild_configure_parameters=$(eval $(echo echo $autobuild_configure_parameters)) eval_autobuild_configure_parameters=$(eval $(echo echo $autobuild_configure_parameters))

View File

@ -278,6 +278,7 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl
catch (std::bad_alloc&) catch (std::bad_alloc&)
{ {
// Out of memory on stack allocation? // Out of memory on stack allocation?
LLError::LLUserWarningMsg::showOutOfMemory();
printActiveCoroutines(); printActiveCoroutines();
LL_ERRS("LLCoros") << "Bad memory allocation in LLCoros::launch(" << prefix << ")!" << LL_ENDL; LL_ERRS("LLCoros") << "Bad memory allocation in LLCoros::launch(" << prefix << ")!" << LL_ENDL;
} }

View File

@ -1619,6 +1619,48 @@ namespace LLError
{ {
return out << boost::stacktrace::stacktrace(); return out << boost::stacktrace::stacktrace();
} }
// LLOutOfMemoryWarning
std::string LLUserWarningMsg::sLocalizedOutOfMemoryTitle;
std::string LLUserWarningMsg::sLocalizedOutOfMemoryWarning;
LLUserWarningMsg::Handler LLUserWarningMsg::sHandler;
void LLUserWarningMsg::show(const std::string& message)
{
if (sHandler)
{
sHandler(std::string(), message);
}
}
void LLUserWarningMsg::showOutOfMemory()
{
if (sHandler && !sLocalizedOutOfMemoryTitle.empty())
{
sHandler(sLocalizedOutOfMemoryTitle, sLocalizedOutOfMemoryWarning);
}
}
void LLUserWarningMsg::showMissingFiles()
{
// Files Are missing, likely can't localize.
const std::string error_string =
"Firestorm viewer couldn't access some of the files it needs and will be closed."
"\n\nPlease reinstall viewer from https://firestormviewer.org/download and "
"contact https://www.firestormviewer.org/support if issue persists after reinstall.";
sHandler("Missing Files", error_string);
}
void LLUserWarningMsg::setHandler(const LLUserWarningMsg::Handler &handler)
{
sHandler = handler;
}
void LLUserWarningMsg::setOutOfMemoryStrings(const std::string& title, const std::string& message)
{
sLocalizedOutOfMemoryTitle = title;
sLocalizedOutOfMemoryWarning = message;
}
} }
void crashdriver(void (*callback)(int*)) void crashdriver(void (*callback)(int*))

View File

@ -39,6 +39,7 @@
#include "llpreprocessor.h" #include "llpreprocessor.h"
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>
#include <functional> // std::function
// <FS:Ansariel> Disable C6011 code analyses warning for now popping up everywhere because of the LL_ENDL / LLERROR_CRASH macro // <FS:Ansariel> Disable C6011 code analyses warning for now popping up everywhere because of the LL_ENDL / LLERROR_CRASH macro
#if LL_WINDOWS #if LL_WINDOWS
@ -313,6 +314,28 @@ namespace LLError
{ {
friend std::ostream& operator<<(std::ostream& out, const LLStacktrace&); friend std::ostream& operator<<(std::ostream& out, const LLStacktrace&);
}; };
// Provides access to OS notification popup on error, since
// not everything has access to OS's messages
class LLUserWarningMsg
{
public:
typedef std::function<void(const std::string&, const std::string&)> Handler;
static void setHandler(const Handler&);
static void setOutOfMemoryStrings(const std::string& title, const std::string& message);
// When viewer encounters bad alloc or can't access files try warning user about reasons
static void showOutOfMemory();
static void showMissingFiles();
// Genering error
static void show(const std::string&);
private:
// needs to be preallocated before viewer runs out of memory
static std::string sLocalizedOutOfMemoryTitle;
static std::string sLocalizedOutOfMemoryWarning;
static Handler sHandler;
};
} }
//this is cheaper than llcallstacks if no need to output other variables to call stacks. //this is cheaper than llcallstacks if no need to output other variables to call stacks.

View File

@ -37,6 +37,7 @@
#include "llerror.h" #include "llerror.h"
#include "llerrorcontrol.h" #include "llerrorcontrol.h"
// used to attach and extract stacktrace information to/from boost::exception, // used to attach and extract stacktrace information to/from boost::exception,
// see https://www.boost.org/doc/libs/release/doc/html/stacktrace/getting_started.html#stacktrace.getting_started.exceptions_with_stacktrace // see https://www.boost.org/doc/libs/release/doc/html/stacktrace/getting_started.html#stacktrace.getting_started.exceptions_with_stacktrace
// apparently the struct passed as the first template param needs no definition? // apparently the struct passed as the first template param needs no definition?

View File

@ -320,6 +320,7 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread)
LLMemory::logMemoryInfo(TRUE); LLMemory::logMemoryInfo(TRUE);
//output possible call stacks to log file. //output possible call stacks to log file.
LLError::LLUserWarningMsg::showOutOfMemory();
LLError::LLCallStacks::print(); LLError::LLCallStacks::print();
LL_ERRS() << "Bad memory allocation in HttpService::threadRun()!" << LL_ENDL; LL_ERRS() << "Bad memory allocation in HttpService::threadRun()!" << LL_ENDL;

View File

@ -321,6 +321,7 @@ bool LLImageBMP::updateData()
mColorPalette = new(std::nothrow) U8[color_palette_size]; mColorPalette = new(std::nothrow) U8[color_palette_size];
if (!mColorPalette) if (!mColorPalette)
{ {
LLError::LLUserWarningMsg::showOutOfMemory();
LL_WARNS() << "Out of memory in LLImageBMP::updateData(), size: " << color_palette_size << LL_ENDL; LL_WARNS() << "Out of memory in LLImageBMP::updateData(), size: " << color_palette_size << LL_ENDL;
return false; return false;
} }

View File

@ -437,6 +437,7 @@ bool LLImageDXT::convertToDXR()
U8* newdata = (U8*)ll_aligned_malloc_16(total_bytes); U8* newdata = (U8*)ll_aligned_malloc_16(total_bytes);
if (!newdata) if (!newdata)
{ {
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Out of memory in LLImageDXT::convertToDXR()" << LL_ENDL; LL_ERRS() << "Out of memory in LLImageDXT::convertToDXR()" << LL_ENDL;
return false; return false;
} }

View File

@ -266,6 +266,7 @@ bool LLImageTGA::updateData()
mColorMap = new(std::nothrow) U8[ color_map_bytes ]; mColorMap = new(std::nothrow) U8[ color_map_bytes ];
if (!mColorMap) if (!mColorMap)
{ {
LLError::LLUserWarningMsg::showOutOfMemory();
LL_WARNS() << "Out of Memory in bool LLImageTGA::updateData(), size: " << color_map_bytes << LL_ENDL; LL_WARNS() << "Out of Memory in bool LLImageTGA::updateData(), size: " << color_map_bytes << LL_ENDL;
return false; return false;
} }

View File

@ -1353,6 +1353,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
scratch = new(std::nothrow) U32[width * height]; scratch = new(std::nothrow) U32[width * height];
if (!scratch) if (!scratch)
{ {
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL; << " bytes for a manual image W" << width << " H" << height << LL_ENDL;
} }
@ -1378,6 +1379,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
scratch = new(std::nothrow) U32[width * height]; scratch = new(std::nothrow) U32[width * height];
if (!scratch) if (!scratch)
{ {
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL; << " bytes for a manual image W" << width << " H" << height << LL_ENDL;
} }
@ -1406,6 +1408,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
scratch = new(std::nothrow) U32[width * height]; scratch = new(std::nothrow) U32[width * height];
if (!scratch) if (!scratch)
{ {
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL; << " bytes for a manual image W" << width << " H" << height << LL_ENDL;
} }

View File

@ -862,7 +862,7 @@ LLRender::~LLRender()
shutdown(); shutdown();
} }
void LLRender::init(bool needs_vertex_buffer) bool LLRender::init(bool needs_vertex_buffer)
{ {
#if LL_WINDOWS #if LL_WINDOWS
if (gGLManager.mHasDebugOutput && gDebugGL) if (gGLManager.mHasDebugOutput && gDebugGL)
@ -884,6 +884,13 @@ void LLRender::init(bool needs_vertex_buffer)
// necessary for reflection maps // necessary for reflection maps
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
#if LL_WINDOWS
if (glGenVertexArrays == nullptr)
{
return false;
}
#endif
{ //bind a dummy vertex array object so we're core profile compliant { //bind a dummy vertex array object so we're core profile compliant
U32 ret; U32 ret;
glGenVertexArrays(1, &ret); glGenVertexArrays(1, &ret);
@ -904,6 +911,8 @@ void LLRender::init(bool needs_vertex_buffer)
stop_glerror(); stop_glerror();
mMaxLineWidthSmooth = range[1]; mMaxLineWidthSmooth = range[1];
// </FS:Ansariel> // </FS:Ansariel>
return true;
} }
void LLRender::initVertexBuffer() void LLRender::initVertexBuffer()

View File

@ -386,7 +386,7 @@ public:
LLRender(); LLRender();
~LLRender(); ~LLRender();
void init(bool needs_vertex_buffer); bool init(bool needs_vertex_buffer);
void initVertexBuffer(); void initVertexBuffer();
void resetVertexBuffer(); void resetVertexBuffer();
void shutdown(); void shutdown();

View File

@ -1562,6 +1562,7 @@ bool LLNotifications::loadTemplates()
if (!success || root.isNull() || !root->hasName( "notifications" )) if (!success || root.isNull() || !root->hasName( "notifications" ))
{ {
LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"));
LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL; LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL;
return false; return false;
} }
@ -1572,6 +1573,7 @@ bool LLNotifications::loadTemplates()
if(!params.validateBlock()) if(!params.validateBlock())
{ {
LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"));
LL_ERRS() << "Problem reading XUI from UI Notifications file: " << base_filename << LL_ENDL; LL_ERRS() << "Problem reading XUI from UI Notifications file: " << base_filename << LL_ENDL;
return false; return false;
} }
@ -1638,6 +1640,7 @@ bool LLNotifications::loadVisibilityRules()
if(!params.validateBlock()) if(!params.validateBlock())
{ {
LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"));
LL_ERRS() << "Problem reading UI Notification Visibility Rules file: " << full_filename << LL_ENDL; LL_ERRS() << "Problem reading UI Notification Visibility Rules file: " << full_filename << LL_ENDL;
return false; return false;
} }

View File

@ -2901,6 +2901,7 @@ BOOL LLTextEditor::importBuffer(const char* buffer, S32 length )
char* text = new char[ text_len + 1]; char* text = new char[ text_len + 1];
if (text == NULL) if (text == NULL)
{ {
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Memory allocation failure." << LL_ENDL; LL_ERRS() << "Memory allocation failure." << LL_ENDL;
return FALSE; return FALSE;
} }

View File

@ -44,8 +44,13 @@ bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::set<s
bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root, LLDir::ALL_SKINS); bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root, LLDir::ALL_SKINS);
if (!success) if (!success)
{ {
const std::string error_string =
"Firestorm viewer couldn't access some of the files it needs and will be closed."
"\n\nPlease reinstall viewer from https://firestormviewer.org/download and "
"contact https://www.firestormviewer.org/support if issue persists after reinstall.";
LLError::LLUserWarningMsg::show(error_string);
gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN);
LL_ERRS() << "Couldn't load string table " << xml_filename << ". Please reinstall viewer from https://www.firestormviewer.org/choose-your-platform/ and contact https://www.firestormviewer.org/support if issue persists after reinstall." << LL_ENDL; LL_ERRS() << "Couldn't load string table " << xml_filename << " " << errno << LL_ENDL;
return false; return false;
} }
@ -60,6 +65,7 @@ bool LLTransUtil::parseLanguageStrings(const std::string& xml_filename)
if (!success) if (!success)
{ {
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Couldn't load localization table " << xml_filename << LL_ENDL; LL_ERRS() << "Couldn't load localization table " << xml_filename << LL_ENDL;
return false; return false;
} }

View File

@ -1 +1 @@
7.1.4 7.1.5

View File

@ -179,6 +179,7 @@ void LLAppCoreHttp::init()
} }
else else
{ {
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS("Init") << "Missing CA File; should be at " << ca_file << LL_ENDL; LL_ERRS("Init") << "Missing CA File; should be at " << ca_file << LL_ENDL;
} }

View File

@ -392,7 +392,6 @@ BOOL gRandomizeFramerate = FALSE;
BOOL gPeriodicSlowFrame = FALSE; BOOL gPeriodicSlowFrame = FALSE;
BOOL gCrashOnStartup = FALSE; BOOL gCrashOnStartup = FALSE;
BOOL gLLErrorActivated = FALSE;
BOOL gLogoutInProgress = FALSE; BOOL gLogoutInProgress = FALSE;
BOOL gSimulateMemLeak = FALSE; BOOL gSimulateMemLeak = FALSE;
@ -2648,9 +2647,6 @@ void errorCallback(LLError::ELevel level, const std::string &error_string)
OSMessageBox(error_display_string, caption, OSMB_OK); OSMessageBox(error_display_string, caption, OSMB_OK);
#endif // !LL_RELEASE_FOR_DOWNLOAD #endif // !LL_RELEASE_FOR_DOWNLOAD
//Set the ErrorActivated global so we know to create a marker file
gLLErrorActivated = true;
gDebugInfo["FatalMessage"] = error_string; gDebugInfo["FatalMessage"] = error_string;
// We're not already crashing -- we simply *intend* to crash. Since we // 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 // haven't actually trashed anything yet, we can afford to write the whole
@ -2659,6 +2655,14 @@ void errorCallback(LLError::ELevel level, const std::string &error_string)
} }
} }
void errorMSG(const std::string& title_string, const std::string& message_string)
{
if (!message_string.empty())
{
OSMessageBox(message_string, title_string.empty() ? LLTrans::getString("MBFatalError") : title_string, OSMB_OK);
}
}
void LLAppViewer::initLoggingAndGetLastDuration() void LLAppViewer::initLoggingAndGetLastDuration()
{ {
// //
@ -2670,6 +2674,8 @@ void LLAppViewer::initLoggingAndGetLastDuration()
LLError::addGenericRecorder(&errorCallback); LLError::addGenericRecorder(&errorCallback);
//LLError::setTimeFunction(getRuntime); //LLError::setTimeFunction(getRuntime);
LLError::LLUserWarningMsg::setHandler(errorMSG);
if (mSecondInstance) if (mSecondInstance)
{ {
@ -2818,6 +2824,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
{ // failed to load { // failed to load
if(file.required) if(file.required)
{ {
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Error: Cannot load required settings file from: " << full_settings_path << LL_ENDL; LL_ERRS() << "Error: Cannot load required settings file from: " << full_settings_path << LL_ENDL;
return false; return false;
} }
@ -2916,6 +2923,7 @@ bool LLAppViewer::initConfiguration()
if (!success) if (!success)
{ {
LL_WARNS() << "Cannot load default configuration file " << settings_file_list << LL_ENDL; LL_WARNS() << "Cannot load default configuration file " << settings_file_list << LL_ENDL;
LLError::LLUserWarningMsg::showMissingFiles();
if (gDirUtilp->fileExists(settings_file_list)) if (gDirUtilp->fileExists(settings_file_list))
{ {
LL_ERRS() << "Cannot load default configuration file settings_files.xml. " LL_ERRS() << "Cannot load default configuration file settings_files.xml. "
@ -2939,6 +2947,7 @@ bool LLAppViewer::initConfiguration()
if (!mSettingsLocationList->validateBlock()) if (!mSettingsLocationList->validateBlock())
{ {
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Invalid settings file list " << settings_file_list << LL_ENDL; LL_ERRS() << "Invalid settings file list " << settings_file_list << LL_ENDL;
} }
@ -3496,6 +3505,8 @@ bool LLAppViewer::initConfiguration()
LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key)); LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key));
} }
LLError::LLUserWarningMsg::setOutOfMemoryStrings(LLTrans::getString("MBOutOfMemoryTitle"), LLTrans::getString("MBOutOfMemoryErr"));
// [RLVa:KB] - Patch: RLVa-2.1.0 // [RLVa:KB] - Patch: RLVa-2.1.0
if (LLControlVariable* pControl = gSavedSettings.getControl(RlvSettingNames::Main)) if (LLControlVariable* pControl = gSavedSettings.getControl(RlvSettingNames::Main))
{ {
@ -3548,6 +3559,7 @@ void LLAppViewer::initStrings()
// initial check to make sure files are there failed // initial check to make sure files are there failed
gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN);
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Viewer failed to find localization and UI files." LL_ERRS() << "Viewer failed to find localization and UI files."
<< " Please reinstall viewer from https://www.firestormviewer.org/downloads" << " Please reinstall viewer from https://www.firestormviewer.org/downloads"
<< " and contact https://www.firestormviewer.org/support if issue persists after reinstall." << LL_ENDL; << " and contact https://www.firestormviewer.org/support if issue persists after reinstall." << LL_ENDL;
@ -5129,6 +5141,7 @@ void LLAppViewer::loadKeyBindings()
key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml"); key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml");
if (!gViewerInput.loadBindingsXML(key_bindings_file)) if (!gViewerInput.loadBindingsXML(key_bindings_file))
{ {
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL;
} }
} }
@ -6292,6 +6305,14 @@ void LLAppViewer::forceErrorLLError()
LL_ERRS() << "This is a deliberate llerror" << LL_ENDL; LL_ERRS() << "This is a deliberate llerror" << LL_ENDL;
} }
void LLAppViewer::forceErrorLLErrorMsg()
{
LLError::LLUserWarningMsg::show("Deliberate error");
// Note: under debug this will show a message as well,
// but release won't show anything and will quit silently
LL_ERRS() << "This is a deliberate llerror with a message" << LL_ENDL;
}
void LLAppViewer::forceErrorBreakpoint() void LLAppViewer::forceErrorBreakpoint()
{ {
LL_WARNS() << "Forcing a deliberate breakpoint" << LL_ENDL; LL_WARNS() << "Forcing a deliberate breakpoint" << LL_ENDL;

View File

@ -149,6 +149,7 @@ public:
// LLAppViewer testing helpers. // LLAppViewer testing helpers.
// *NOTE: These will potentially crash the viewer. Only for debugging. // *NOTE: These will potentially crash the viewer. Only for debugging.
virtual void forceErrorLLError(); virtual void forceErrorLLError();
virtual void forceErrorLLErrorMsg();
virtual void forceErrorBreakpoint(); virtual void forceErrorBreakpoint();
virtual void forceErrorBadMemoryAccess(); virtual void forceErrorBadMemoryAccess();
virtual void forceErrorInfiniteLoop(); virtual void forceErrorInfiniteLoop();

View File

@ -339,6 +339,7 @@ void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regio
} }
catch (std::bad_alloc&) catch (std::bad_alloc&)
{ {
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "LLCoros::launch() allocation failure" << LL_ENDL; LL_ERRS() << "LLCoros::launch() allocation failure" << LL_ENDL;
} }
} }
@ -370,6 +371,7 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi
} }
catch (std::bad_alloc&) catch (std::bad_alloc&)
{ {
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "LLCoros::launch() allocation failure" << LL_ENDL; LL_ERRS() << "LLCoros::launch() allocation failure" << LL_ENDL;
} }
} }

View File

@ -1430,7 +1430,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry)
U8* buffer = new(std::nothrow) U8[size]; U8* buffer = new(std::nothrow) U8[size];
if (!buffer) if (!buffer)
{ {
LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for skin info, size: " << size << LL_ENDL; LL_WARNS(LOG_MESH) << "Failed to allocate memory for skin info, size: " << size << LL_ENDL;
return false; return false;
} }
LLMeshRepository::sCacheBytesRead += size; LLMeshRepository::sCacheBytesRead += size;
@ -1550,7 +1550,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
U8* buffer = new(std::nothrow) U8[size]; U8* buffer = new(std::nothrow) U8[size];
if (!buffer) if (!buffer)
{ {
LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for mesh decomposition, size: " << size << LL_ENDL; LL_WARNS(LOG_MESH) << "Failed to allocate memory for mesh decomposition, size: " << size << LL_ENDL;
return false; return false;
} }
LLMeshRepository::sCacheBytesRead += size; LLMeshRepository::sCacheBytesRead += size;
@ -1659,7 +1659,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
U8* buffer = new(std::nothrow) U8[size]; U8* buffer = new(std::nothrow) U8[size];
if (!buffer) if (!buffer)
{ {
LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for physics shape, size: " << size << LL_ENDL; LL_WARNS(LOG_MESH) << "Failed to allocate memory for physics shape, size: " << size << LL_ENDL;
return false; return false;
} }
file.read(buffer, size); file.read(buffer, size);
@ -1868,7 +1868,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,
U8* buffer = new(std::nothrow) U8[size]; U8* buffer = new(std::nothrow) U8[size];
if (!buffer) if (!buffer)
{ {
LL_WARNS_ONCE(LOG_MESH) << "Can't allocate memory for mesh " << mesh_id << " LOD " << lod << ", size: " << size << LL_ENDL; LL_WARNS(LOG_MESH) << "Can't allocate memory for mesh " << mesh_id << " LOD " << lod << ", size: " << size << LL_ENDL;
// todo: for now it will result in indefinite constant retries, should result in timeout // todo: for now it will result in indefinite constant retries, should result in timeout
// or in retry-count and disabling mesh. (but usually viewer is beyond saving at this point) // or in retry-count and disabling mesh. (but usually viewer is beyond saving at this point)
return false; return false;

View File

@ -352,6 +352,7 @@ void handle_disconnect_viewer(void *);
void force_error_breakpoint(void *); void force_error_breakpoint(void *);
void force_error_llerror(void *); void force_error_llerror(void *);
void force_error_llerror_msg(void*);
void force_error_bad_memory_access(void *); void force_error_bad_memory_access(void *);
void force_error_infinite_loop(void *); void force_error_infinite_loop(void *);
void force_error_software_exception(void *); void force_error_software_exception(void *);
@ -2719,6 +2720,15 @@ class LLAdvancedForceErrorLlerror : public view_listener_t
} }
}; };
class LLAdvancedForceErrorLlerrorMsg: public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
force_error_llerror_msg(NULL);
return true;
}
};
class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t
{ {
bool handleEvent(const LLSD& userdata) bool handleEvent(const LLSD& userdata)
@ -10732,6 +10742,11 @@ void force_error_llerror(void *)
LLAppViewer::instance()->forceErrorLLError(); LLAppViewer::instance()->forceErrorLLError();
} }
void force_error_llerror_msg(void*)
{
LLAppViewer::instance()->forceErrorLLErrorMsg();
}
void force_error_bad_memory_access(void *) void force_error_bad_memory_access(void *)
{ {
LLAppViewer::instance()->forceErrorBadMemoryAccess(); LLAppViewer::instance()->forceErrorBadMemoryAccess();
@ -12417,6 +12432,7 @@ void initialize_menus()
// Advanced > Debugging // Advanced > Debugging
view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint"); view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint");
view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror"); view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror");
view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg");
view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess"); view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess");
view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro"); view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro");
view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop");

View File

@ -2067,7 +2067,11 @@ LLViewerWindow::LLViewerWindow(const Params& p)
// Initialize OpenGL Renderer // Initialize OpenGL Renderer
LLVertexBuffer::initClass(mWindow); LLVertexBuffer::initClass(mWindow);
LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ; LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ;
gGL.init(true); if (!gGL.init(true))
{
LLError::LLUserWarningMsg::show(LLTrans::getString("MBVideoDrvErr"));
LL_ERRS() << "gGL not initialized" << LL_ENDL;
}
// <FS:Ansariel> Exodus vignette // <FS:Ansariel> Exodus vignette
if (LLFeatureManager::getInstance()->isSafe() if (LLFeatureManager::getInstance()->isSafe()

View File

@ -455,6 +455,7 @@
<menu label="Fehler erzwingen" name="Force Errors"> <menu label="Fehler erzwingen" name="Force Errors">
<menu_item_call label="Haltepunkt erzwingen" name="Force Breakpoint"/> <menu_item_call label="Haltepunkt erzwingen" name="Force Breakpoint"/>
<menu_item_call label="LLError erzwingen und abstürzen" name="Force LLError And Crash"/> <menu_item_call label="LLError erzwingen und abstürzen" name="Force LLError And Crash"/>
<menu_item_call label="LLError erzwingen, Meldung anzeigen und abstürzen" name="Force LLError Message And Crash"/>
<menu_item_call label="Fehlerhaften Speicherzugriff erzwingen" name="Force Bad Memory Access"/> <menu_item_call label="Fehlerhaften Speicherzugriff erzwingen" name="Force Bad Memory Access"/>
<menu_item_call label="Fehlerhaften Speicherzugriff in Coroutine erzwingen" name="Force Bad Memory Access in Coroutine"/> <menu_item_call label="Fehlerhaften Speicherzugriff in Coroutine erzwingen" name="Force Bad Memory Access in Coroutine"/>
<menu_item_call label="Endlosschleife erzwingen" name="Force Infinite Loop"/> <menu_item_call label="Endlosschleife erzwingen" name="Force Infinite Loop"/>

View File

@ -3300,6 +3300,17 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_
[APP_NAME] kann nicht ausgeführt werden, da die Treiber Ihrer Videokarte entweder nicht richtig installiert oder veraltet sind, oder die entsprechende Hardware nicht unterstützt wird. Bitte vergewissern Sie sich, dass Sie die aktuellsten Treiber für die Videokarte installiert haben. Falls Sie die aktuellsten Treiber bereits installiert haben, installieren Sie diese bitte erneut. [APP_NAME] kann nicht ausgeführt werden, da die Treiber Ihrer Videokarte entweder nicht richtig installiert oder veraltet sind, oder die entsprechende Hardware nicht unterstützt wird. Bitte vergewissern Sie sich, dass Sie die aktuellsten Treiber für die Videokarte installiert haben. Falls Sie die aktuellsten Treiber bereits installiert haben, installieren Sie diese bitte erneut.
Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_SITE]. Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_SITE].
</string>
<string name="MBOutOfMemoryTitle">Kein Arbeitsspeicher verfügbar</string>
<string name="MBOutOfMemoryErr">
Die Anfrage nach Arbeitsspeicher durch [APP_NAME] is fehlgeschlagen. Die Anwendung kann nicht fortgesetzt werden und wird beendet.
Falls wenig Arbeitsspeicher auf Ihrem Computers verfügbar ist, beenden Sie andere speicherintensiven Anwendungen, bevor sie [APP_NAME] ausführen, vergrößern Sie die Auslagerungsdatei oder verringern Sie Grafikeinstellungen wie Sichtweite.
</string>
<string name="MBMissingFile">
[APP_NAME] konnte einige der benötigten Dateien nicht finden oder auf sie zugreifen und muss daher beendet werden.
Bitte installieren Sie den Viewer von [DOWNLOAD_URL] erneut und wenden Sie sich an [SUPPORT_SITE] falls das Problem nach einer Neuinstallation weiterhin besteht.
</string> </string>
<string name="5 O'Clock Shadow"> <string name="5 O'Clock Shadow">
Bartschatten Bartschatten

View File

@ -4002,6 +4002,12 @@
<menu_item_call.on_click <menu_item_call.on_click
function="Advanced.ForceErrorLlerror" /> function="Advanced.ForceErrorLlerror" />
</menu_item_call> </menu_item_call>
<menu_item_call
label="Force LLError, Message And Crash"
name="Force LLError Message And Crash">
<menu_item_call.on_click
function="Advanced.ForceErrorLlerrorMsg" />
</menu_item_call>
<menu_item_call <menu_item_call
label="Force Bad Memory Access" label="Force Bad Memory Access"
name="Force Bad Memory Access"> name="Force Bad Memory Access">

View File

@ -1521,8 +1521,19 @@ Running in window.
If you continue to receive this message, contact the [SUPPORT_SITE]. If you continue to receive this message, contact the [SUPPORT_SITE].
</string> </string>
<string name="MBOutOfMemoryTitle">Out Of Memory</string>
<string name="MBOutOfMemoryErr">
[APP_NAME]'s request for memory failed. Application can't proceed and will be closed.
<!-- Avatar Shape Information --> If your computer's RAM is low, quit any heavy applications before runing [APP_NAME], allocate a page file or reduce graphical settings like draw distance.
</string>
<string name="MBMissingFile">
[APP_NAME] couldn't access or find some of the files it needs and will be closed.
Please reinstall viewer from [DOWNLOAD_URL] and contact [SUPPORT_SITE] if issue persists after reinstall.
</string>
<!-- Avatar Shape Information -->
<string name="5 O'Clock Shadow">5 O'Clock Shadow</string> <string name="5 O'Clock Shadow">5 O'Clock Shadow</string>
<string name="All White">All White</string> <string name="All White">All White</string>