diff --git a/autobuild.xml b/autobuild.xml index d173b9eee0..fdfdedec19 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3,6 +3,36 @@ installables + SDL2 + + copyright + Copyright (C) 1997-2022 Sam Lantinga + description + Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer. + license + zlib + license_file + LICENSES/SDL.txt + name + SDL2 + platforms + + linux64 + + archive + + hash + f332d752a72cb524eb5db8ee6fdba3da + url + http://3p.firestormviewer.org/SDL2-2.0.20-linux64_bionic-221151857.tar.bz2 + + name + linux64 + + + version + 1.2.15 + gstreamer10 copyright diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 21f9faa410..0f69fb7fa0 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -115,28 +115,28 @@ else (USESYSTEMLIBS) elseif (DARWIN) set(BOOST_CONTEXT_LIBRARY optimized boost_context-mt${addrsfx} - debug boost_context-mt${addrsfx}-d) + debug boost_context-mt${addrsfx}) set(BOOST_FIBER_LIBRARY optimized boost_fiber-mt${addrsfx} - debug boost_fiber-mt${addrsfx}-d) + debug boost_fiber-mt${addrsfx}) set(BOOST_FILESYSTEM_LIBRARY optimized boost_filesystem-mt${addrsfx} - debug boost_filesystem-mt${addrsfx}-d) + debug boost_filesystem-mt${addrsfx}) set(BOOST_PROGRAM_OPTIONS_LIBRARY optimized boost_program_options-mt${addrsfx} - debug boost_program_options-mt${addrsfx}-d) + debug boost_program_options-mt${addrsfx}) set(BOOST_REGEX_LIBRARY optimized boost_regex-mt${addrsfx} - debug boost_regex-mt${addrsfx}-d) + debug boost_regex-mt${addrsfx}) set(BOOST_SIGNALS_LIBRARY optimized boost_signals-mt${addrsfx} - debug boost_signals-mt${addrsfx}-d) + debug boost_signals-mt${addrsfx}) set(BOOST_SYSTEM_LIBRARY optimized boost_system-mt${addrsfx} - debug boost_system-mt${addrsfx}-d) + debug boost_system-mt${addrsfx}) set(BOOST_THREAD_LIBRARY optimized boost_thread-mt${addrsfx} - debug boost_thread-mt${addrsfx}-d) + debug boost_thread-mt${addrsfx}) set(BOOST_WAVE_LIBRARY optimized boost_wave-mt${addrsfx} debug boost_wave-mt${addrsfx}-gd) diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake index 398647e58f..5fb05696e5 100644 --- a/indra/cmake/LLWindow.cmake +++ b/indra/cmake/LLWindow.cmake @@ -15,9 +15,16 @@ if (USESYSTEMLIBS) ) else (USESYSTEMLIBS) if (LINUX) - use_prebuilt_binary(SDL) - set (SDL_FOUND TRUE) - set (SDL_LIBRARY SDL directfb fusion direct X11) + if( NOT USE_SDL2 ) + use_prebuilt_binary(SDL) + set (SDL_FOUND TRUE) + set (SDL_LIBRARY SDL directfb fusion direct X11) + else() + use_prebuilt_binary(SDL2) + set (SDL2_FOUND TRUE) + set (SDL_LIBRARY SDL2 SDL2_mixer X11) + endif() + endif (LINUX) endif (USESYSTEMLIBS) diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake index de567bdba0..e00413b1a4 100644 --- a/indra/cmake/UI.cmake +++ b/indra/cmake/UI.cmake @@ -61,7 +61,7 @@ else (USESYSTEMLIBS) set(UI_LIBRARIES ${UI_LIBRARIES} ${UI_LIB_${libname}}) endforeach(libname) - set(UI_LIBRARIES ${UI_LIBRARIES} Xinerama) + set(UI_LIBRARIES ${UI_LIBRARIES} Xinerama X11) include_directories ( ${GLIB_INCLUDE_DIRS} ) endif (LINUX) diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 804b36b226..18c262cb00 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -10,6 +10,7 @@ include(LLCommon) include(LLMath) include(LLMessage) include(LLFileSystem) +include(LLWindow) include_directories( SYSTEM ${LLAUDIO_INCLUDE_DIRS} @@ -75,6 +76,11 @@ if (OPENAL) ) endif (OPENAL) +if(SDL2_FOUND) + list(APPEND llaudio_SOURCE_FILES llaudioengine_sdl2.cpp ) + list(APPEND llaudio_HEADER_FILES llaudioengine_sdl2.h ) +endif() + set_source_files_properties(${llaudio_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) diff --git a/indra/llaudio/llaudioengine_sdl2.cpp b/indra/llaudio/llaudioengine_sdl2.cpp new file mode 100644 index 0000000000..468ddccfeb --- /dev/null +++ b/indra/llaudio/llaudioengine_sdl2.cpp @@ -0,0 +1,489 @@ +#include "llaudioengine_sdl2.h" +#include "llstreamingaudio.h" +#include "lllistener.h" + +#include "SDL2/SDL_mixer.h" + +#include "curl/curl.h" + +namespace +{ + std::string getMixerError() + { + auto pError = Mix_GetError(); + if(!pError) + return "Mix_Error: returned nullptr"; + + return std::string{ "Mix_error: " } + pError; + } +} + +struct RWData +{ + std::string mURL; + CURLM *mMulti{ nullptr }; + CURL *mEasy{ nullptr }; +}; + +Sint64 SDLCALL stream_size (struct SDL_RWops * context) +{ + return -1; +} + +Sint64(SDLCALL stream_seek) (struct SDL_RWops * context, Sint64 offset, + int whence) +{ + if( !context ) + return -1; + + RWData *pData = reinterpret_cast(context->hidden.unknown.data1); + return -1; +} + +size_t SDLCALL stream_read (struct SDL_RWops * context, void *ptr, size_t size, size_t maxnum) +{ + if( !context ) + return 0; + + RWData *pData = reinterpret_cast(context->hidden.unknown.data1); + return 0; +} + +size_t SDLCALL stream_write (struct SDL_RWops * context, const void *ptr, + size_t size, size_t num) +{ + if( !context ) + return 0; + + RWData *pData = reinterpret_cast(context->hidden.unknown.data1); + return 0; +} + +int SDLCALL stream_close (struct SDL_RWops * context) +{ + if( !context ) + return 0; + + RWData *pData = reinterpret_cast(context->hidden.unknown.data1); + // Free curl multi and easy + + + return 0; +} + + +class LLListenerSDL2: public LLListener +{ + LLAudioEngineSDL2 *mEngine; +public: + LLListenerSDL2(LLAudioEngineSDL2 *aEngine ) + : mEngine( aEngine ) + { + + } + +}; + +class LLStreamingAudioSDL2: public LLStreamingAudioInterface +{ + std::string mURL; + F32 mVolume { 1.0 }; + Mix_Music *mMusic{nullptr}; + SDL_RWops *mReader{ nullptr }; + RWData *mData; +public: + + void start(const std::string& url) override + { + mURL = url; + //mMusic = Mix_LoadMUS( url.c_str() ); + mReader = SDL_AllocRW(); + mData = new RWData{}; + mReader->hidden.unknown.data1 = mData; + + mReader->size = stream_size; + mReader->seek = stream_seek; + mReader->read = stream_read; + mReader->write = stream_write; + mReader->close = stream_close; + + mMusic = Mix_LoadMUS_RW( mReader, 0 ); + if( mMusic ) + { + auto x = Mix_PlayMusic( mMusic, 0 ); + LL_WARNS() << "SDL2: " << getMixerError() << " " << x << LL_ENDL; + } + else + { + LL_WARNS() << "SDL2: MixLoadMUS failed: " << getMixerError() << LL_ENDL; + } + + } + + void stop() override + { + } + + void pause(int pause) override + { + } + + void update() override + { + } + + int isPlaying() override + { + return mMusic != nullptr; + } + + void setGain(F32 vol) override + { + mVolume = vol; + } + + F32 getGain() override + { + return mVolume; + } + + std::string getURL() override + { + return mURL; + } + + bool supportsAdjustableBufferSizes() override + { + return false; + } + + void setBufferSizes(U32 streambuffertime, U32 decodebuffertime) override + { + } +}; + +class LLAudioBufferSDL2: public LLAudioBuffer +{ +public: + Mix_Chunk *mChunk; + + ~LLAudioBufferSDL2() + { + if( mChunk ) + Mix_FreeChunk(mChunk); + } + + bool loadWAV(const std::string& filename) + { + mChunk = Mix_LoadWAV( filename.c_str() ); + return mChunk != nullptr; + } + + U32 getLength() + { + return 0; // Not needed here + } + +}; + +class LLAudioChannelSDL2: public LLAudioChannel +{ + S32 mChannel; + LLAudioEngineSDL2 *mEngine; + bool mPlayback{false}; + + uint32_t caclulateVolume() + { + if( mChannel < 0 || !mCurrentSourcep || !mEngine) + return 0.0f; + + + F32 gain = mCurrentSourcep->getGain() * getSecondaryGain() * mEngine->getMasterGain(); + llclamp(gain, 0.0f, 1.f ); + gain *= 255.f; + return static_cast(gain); + + } +public: + LLAudioChannelSDL2( S32 nChannel, LLAudioEngineSDL2 *aEngine ) + : mChannel( nChannel ) + , mEngine( aEngine ) + { + + } + + ~LLAudioChannelSDL2() + { + mEngine->deleteChannel( mChannel ); + } + + void play() override + { + startPlayback(); + } + + void startPlayback() + { + if( mChannel < 0 ) + return; + + //if( mPlayback ) + // return; + + Mix_HaltChannel( mChannel ); + LLAudioBufferSDL2* pBuffer = (LLAudioBufferSDL2*)mCurrentBufferp; + if( !pBuffer ) + return; + + mPlayback = true; + Mix_PlayChannel( mChannel, pBuffer->mChunk, mCurrentSourcep->isLoop()?-1:0 ); + Mix_Volume( mChannel, caclulateVolume()); + } + + void playSynced(LLAudioChannel *channelp) override + { + play(); + } + + void cleanup() override + { + if( mChannel < 0 ) + return; + + mPlayback = false; + Mix_HaltChannel( mChannel ); + } + + bool isPlaying() override + { + if( mChannel < 0 ) + return false; + + if( !mPlayback ) + return false; + + bool bRet = Mix_Playing( mChannel ) == 1; + if( !bRet ) + { + mPlayback = false; + Mix_HaltChannel( mChannel ); + } + + return bRet; + } + + bool updateBuffer() override + { + if( !mCurrentSourcep || mChannel < 0) + return false; + + if( LLAudioChannel::updateBuffer() ) + { + if(mCurrentSourcep) + { + startPlayback(); + return true; + } + } + else if( mCurrentSourcep ) + { + if( mPlayback ) + Mix_Volume( mChannel, caclulateVolume()); + } + else + { + if( mPlayback ) + Mix_HaltChannel(mChannel); + mPlayback = false; + } + return mCurrentSourcep != 0; + } + + void update3DPosition() override + { + if(!mCurrentSourcep || mChannel < 0) + return; + + if(mPlayback) + { + auto pos = mEngine->getListenerPos(); + LLVector3 soundpos{mCurrentSourcep->getPositionGlobal()}; + F32 dist = dist_vec(soundpos, pos); + dist = llclamp(dist, 0.0f, 255.0f); + Mix_SetPosition(mChannel, 0, (uint8_t) dist); + } + } + + void updateLoop() override + { + } + +}; + +struct LLAudioEngineSDL2::ImplData +{ + std::vector< uint8_t > mChannels; + bool mReady { false }; +}; + +LLAudioEngineSDL2::LLAudioEngineSDL2() +{ + +} + +LLAudioEngineSDL2::~LLAudioEngineSDL2() +{ + +} + +bool LLAudioEngineSDL2::init(const S32 num_channels, void *userdata, const std::string &app_title) +{ + LL_INFOS() << "Initializing SDL2 audio" << LL_ENDL; + mData = std::make_unique(); + + LLAudioEngine::init(num_channels, userdata, app_title); + + int flags = MIX_INIT_FLAC | MIX_INIT_MP3 | MIX_INIT_MP3; + if( flags != Mix_Init( flags ) ) + LL_WARNS() << "Mix_Init failed to intialize all formats: " << getMixerError () << LL_ENDL; + + if( 0 != Mix_OpenAudio(44100, AUDIO_S16LSB, MIX_DEFAULT_CHANNELS, 1024 ) ) + { + LL_WARNS() << "Mix_OpenAudio failed " << getMixerError() << LL_ENDL; + return false; + } + mData->mChannels.resize( num_channels+2 ); + Mix_AllocateChannels( num_channels ); + mData->mReady = true; + + // Impl is stubbed out, but nothing more +// if (!getStreamingAudioImpl()) +// setStreamingAudioImpl( new LLStreamingAudioSDL2() ); + + + return true; + +} +std::string LLAudioEngineSDL2::getDriverName(bool verbose) +{ + return "SDL mixer"; +} + +void LLAudioEngineSDL2::shutdown() +{ + Mix_CloseAudio(); + Mix_Quit(); + + mData = nullptr; +} + +void LLAudioEngineSDL2::updateWind(LLVector3 direction, F32 camera_height_above_water) +{ + +} + +void LLAudioEngineSDL2::idle(F32 max_decode_time ) +{ + LLAudioEngine::idle(max_decode_time); +} + +void LLAudioEngineSDL2::updateChannels() +{ + LLAudioEngine::updateChannels(); +} + +LLAudioEngineSDL2::output_device_map_t LLAudioEngineSDL2::getDevices() +{ +// Impl looks like this, but it might not be possible to support this right now +/* + if(mDevices.size()) + return; + + auto numDevices{SDL_GetNumAudioDevices(0)}; + if( numDevices <= 0 ) + return {}; + + LLAudioEngineSDL2::output_device_map_t devices{}; + for( auto i{0}; i < numDevices; ++i ) + { + auto pName{SDL_GetAudioDeviceName(i, 0)}; + if( !pName ) + continue; + + std::string strName{ pName }; + + devices[ LLUUID::generateNewID( strName )] = strName; + } +*/ + + return mDevices; +} + +void LLAudioEngineSDL2::setDevice(const LLUUID &device_uuid) +{ + +} + +LLAudioBuffer *LLAudioEngineSDL2::createBuffer() +{ + return new LLAudioBufferSDL2(); +} + +LLAudioChannel *LLAudioEngineSDL2::createChannel() +{ + S32 channelNum{ -1 }; + if( mData && mData->mReady ) + { + for( S32 i = 0; i < mData->mChannels.size(); ++i ) + { + if( !mData->mChannels[i]) + { + channelNum = i; + mData->mChannels[i] = 1; + break; + } + } + + if( channelNum == -1 ) + { + channelNum = mData->mChannels.size(); + mData->mChannels.push_back(0); + Mix_AllocateChannels( mData->mChannels.size() ); + } + } + + return new LLAudioChannelSDL2(channelNum, this); +} + +void LLAudioEngineSDL2::deleteChannel(S32 aChannel) +{ + if( !mData ) + return; + + if( aChannel < 0 || aChannel >= mData->mChannels.size() ) + return; + + mData->mChannels[aChannel] = 0; +} + +bool LLAudioEngineSDL2::initWind() +{ + // Not supported + return false; +} + +void LLAudioEngineSDL2::cleanupWind() +{ + +} + +void LLAudioEngineSDL2::setInternalGain(F32 gain) +{ + +} + +void LLAudioEngineSDL2::allocateListener() +{ + mListenerp = new LLListenerSDL2(this); +} + diff --git a/indra/llaudio/llaudioengine_sdl2.h b/indra/llaudio/llaudioengine_sdl2.h new file mode 100644 index 0000000000..1c501b6e1a --- /dev/null +++ b/indra/llaudio/llaudioengine_sdl2.h @@ -0,0 +1,43 @@ +#ifndef LL_AUDIOENGINE_SDL2_H +#define LL_AUDIOENGINE_SDL2_H + +#include "llaudioengine.h" +#include "llwindgen.h" + +class LLAudioEngineSDL2 : public LLAudioEngine +{ +public: + LLAudioEngineSDL2(); + ~LLAudioEngineSDL2(); + + bool init(const S32 num_channels, void *userdata, const std::string &app_title) override; + std::string getDriverName(bool verbose) override; + void shutdown() override; + + void updateWind(LLVector3 direction, F32 camera_height_above_water) override; + void idle(F32 max_decode_time = 0.f) override; + void updateChannels() override; + + output_device_map_t getDevices() override; + void setDevice(const LLUUID& device_uuid) override; + + + void deleteChannel( S32 aChannel ); + +protected: + LLAudioBuffer *createBuffer() override; + LLAudioChannel *createChannel() override; + + bool initWind() override; + void cleanupWind() override; + void setInternalGain(F32 gain) override; + + void allocateListener() override; + + output_device_map_t mDevices; + + struct ImplData; + std::unique_ptr< ImplData > mData; +}; + +#endif \ No newline at end of file diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index baab09a104..d414ec78c5 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -112,10 +112,15 @@ endif (BUILD_HEADLESS) add_library (llrender ${llrender_SOURCE_FILES}) if (SDL_FOUND) - set_property(TARGET llrender - PROPERTY COMPILE_DEFINITIONS LL_SDL=1 - ) + set_property(TARGET llrender + PROPERTY COMPILE_DEFINITIONS LL_SDL=1 + ) endif (SDL_FOUND) +if (SDL2_FOUND) + set_property(TARGET llrender + PROPERTY COMPILE_DEFINITIONS LL_SDL2=1 LL_SDL=1 + ) +endif () # Libraries on which this library depends, needed for Linux builds # Sort by high-level to low-level diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 53e4df3825..64f722e94e 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -81,15 +81,25 @@ if (LINUX) libfreetype.a ) - list(APPEND viewer_SOURCE_FILES - llkeyboardsdl.cpp - llwindowsdl.cpp - ) - list(APPEND viewer_HEADER_FILES - llkeyboardsdl.h - llwindowsdl.h - ) - + if( NOT USE_SDL2 ) + list(APPEND viewer_SOURCE_FILES + llkeyboardsdl.cpp + llwindowsdl.cpp + ) + list(APPEND viewer_HEADER_FILES + llkeyboardsdl.h + llwindowsdl.h + ) + else() + list(APPEND viewer_SOURCE_FILES + llkeyboardsdl2.cpp + llwindowsdl2.cpp + ) + list(APPEND viewer_HEADER_FILES + llkeyboardsdl2.h + llwindowsdl2.h + ) + endif() if (BUILD_HEADLESS) set(llwindowheadless_LINK_LIBRARIES ${LLCOMMON_LIBRARIES} @@ -193,9 +203,14 @@ endif (llwindow_HEADER_FILES) if (SDL_FOUND) set_property(TARGET llwindow - PROPERTY COMPILE_DEFINITIONS LL_SDL=1 - ) -endif (SDL_FOUND) + PROPERTY COMPILE_DEFINITIONS LL_SDL=1 + ) +endif () +if (SDL2_FOUND) + set_property(TARGET llwindow + PROPERTY COMPILE_DEFINITIONS LL_SDL2=1 LL_SDL=1 + ) +endif () - target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES}) +target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES}) diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index e65cc7563e..0711356afb 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -195,12 +195,12 @@ void LLKeyboard::resetKeys() } -BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key) +// SDL2 compat +//BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key) +BOOL LLKeyboard::translateKey(const NATIVE_KEY_TYPE os_key, KEY *out_key) { - std::map::iterator iter; - // Only translate keys in the map, ignore all other keys for now - iter = mTranslateKeyMap.find(os_key); + auto iter = mTranslateKeyMap.find(os_key); if (iter == mTranslateKeyMap.end()) { //LL_WARNS() << "Unknown virtual key " << os_key << LL_ENDL; @@ -215,10 +215,11 @@ BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key) } -U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) +// SDL2 compat +//U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) +LLKeyboard::NATIVE_KEY_TYPE LLKeyboard::inverseTranslateKey(const KEY translated_key) { - std::map::iterator iter; - iter = mInvTranslateKeyMap.find(translated_key); + auto iter = mInvTranslateKeyMap.find(translated_key); if (iter == mInvTranslateKeyMap.end()) { return 0; diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index fb1ae10f50..c067cdd034 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -55,6 +55,14 @@ class LLWindowCallbacks; class LLKeyboard { public: + // For SDL2 input is widened to U32 symbols +#ifndef LL_SDL2 + typedef U16 NATIVE_KEY_TYPE; +#else + typedef U32 NATIVE_KEY_TYPE; +#endif + // + LLKeyboard(); virtual ~LLKeyboard(); @@ -67,15 +75,22 @@ public: BOOL getKeyDown(const KEY key) { return mKeyLevel[key]; } BOOL getKeyRepeated(const KEY key) { return mKeyRepeated[key]; } - BOOL translateKey(const U16 os_key, KEY *translated_key); - U16 inverseTranslateKey(const KEY translated_key); + // SDL2 compat + //BOOL translateKey(const U16 os_key, KEY *translated_key); + //U16 inverseTranslateKey(const KEY translated_key); + BOOL translateKey(const NATIVE_KEY_TYPE os_key, KEY *translated_key); + NATIVE_KEY_TYPE inverseTranslateKey(const KEY translated_key); + // BOOL handleTranslatedKeyUp(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes BOOL handleTranslatedKeyDown(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes + // SDL2 compat + //virtual BOOL handleKeyUp(const U16 key, MASK mask) = 0; + //virtual BOOL handleKeyDown(const U16 key, MASK mask) = 0; + virtual BOOL handleKeyUp(const NATIVE_KEY_TYPE key, MASK mask) = 0; + virtual BOOL handleKeyDown(const NATIVE_KEY_TYPE key, MASK mask) = 0; + // - virtual BOOL handleKeyUp(const U16 key, MASK mask) = 0; - virtual BOOL handleKeyDown(const U16 key, MASK mask) = 0; - #ifdef LL_DARWIN // We only actually use this for OS X. virtual void handleModifier(MASK mask) = 0; @@ -109,8 +124,13 @@ protected: void addKeyName(KEY key, const std::string& name); protected: - std::map mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs - std::map mInvTranslateKeyMap; // Map of translations from Linden KEYs to OS keys + // SDL2 compat + //std::map mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs + //std::map mInvTranslateKeyMap; // Map of translations from Linden KEYs to OS keys + std::map mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs + std::map mInvTranslateKeyMap; // Map of translations from Linden KEYs to OS keys + // + LLWindowCallbacks *mCallbacks; LLTimer mKeyLevelTimer[KEY_COUNT]; // Time since level was set diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp index a1b6b294e0..cf52591fa7 100644 --- a/indra/llwindow/llkeyboardheadless.cpp +++ b/indra/llwindow/llkeyboardheadless.cpp @@ -34,14 +34,6 @@ LLKeyboardHeadless::LLKeyboardHeadless() void LLKeyboardHeadless::resetMaskKeys() { } - -BOOL LLKeyboardHeadless::handleKeyDown(const U16 key, const U32 mask) -{ return FALSE; } - - -BOOL LLKeyboardHeadless::handleKeyUp(const U16 key, const U32 mask) -{ return FALSE; } - MASK LLKeyboardHeadless::currentMask(BOOL for_mouse_event) { return MASK_NONE; } diff --git a/indra/llwindow/llkeyboardheadless.h b/indra/llwindow/llkeyboardheadless.h index 8ed28ace90..ee92c07024 100644 --- a/indra/llwindow/llkeyboardheadless.h +++ b/indra/llwindow/llkeyboardheadless.h @@ -35,8 +35,13 @@ public: LLKeyboardHeadless(); /*virtual*/ ~LLKeyboardHeadless() {}; - /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask); - /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask); +#ifndef LL_SDL2 + /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask) { return FALSE; } + /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask) { return FALSE; } +#else + /*virtual*/ BOOL handleKeyUp(const U32 key, MASK mask) { return FALSE; } + /*virtual*/ BOOL handleKeyDown(const U32 key, MASK mask) { return FALSE; } +#endif /*virtual*/ void resetMaskKeys(); /*virtual*/ MASK currentMask(BOOL for_mouse_event); /*virtual*/ void scanKeyboard(); diff --git a/indra/llwindow/llkeyboardsdl.h b/indra/llwindow/llkeyboardsdl.h index 02a71425f1..c8346c07d4 100644 --- a/indra/llwindow/llkeyboardsdl.h +++ b/indra/llwindow/llkeyboardsdl.h @@ -24,6 +24,10 @@ * $/LicenseInfo$ */ +#ifdef LL_SDL2 +#include "llkeyboardsdl2.h" +#else + #ifndef LL_LLKEYBOARDSDL_H #define LL_LLKEYBOARDSDL_H @@ -53,3 +57,4 @@ private: }; #endif +#endif \ No newline at end of file diff --git a/indra/llwindow/llkeyboardsdl2.cpp b/indra/llwindow/llkeyboardsdl2.cpp new file mode 100644 index 0000000000..c75c081055 --- /dev/null +++ b/indra/llwindow/llkeyboardsdl2.cpp @@ -0,0 +1,642 @@ + +#if LL_SDL2 + +#include "linden_common.h" +#include "llkeyboardsdl2.h" +#include "llwindowcallbacks.h" +#include "SDL2/SDL.h" +#include "SDL2/SDL_keycode.h" + +LLKeyboardSDL::LLKeyboardSDL() +{ + // Set up key mapping for SDL - eventually can read this from a file? + // Anything not in the key map gets dropped + // Add default A-Z + + // Virtual key mappings from SDL_keysym.h ... + + // SDL maps the letter keys to the ASCII you'd expect, but it's lowercase... + + // Looks like we need to map those despite of SDL_TEXTINPUT handling most of this, but without + // the translation lower->upper here accelerators will not work. + + U16 cur_char; + for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) + { + mTranslateKeyMap[cur_char] = cur_char; + } + for (cur_char = 'a'; cur_char <= 'z'; cur_char++) + { + mTranslateKeyMap[cur_char] = (cur_char - 'a') + 'A'; + } + + for (cur_char = '0'; cur_char <= '9'; cur_char++) + { + mTranslateKeyMap[cur_char] = cur_char; + } + + // These ones are translated manually upon keydown/keyup because + // SDL doesn't handle their numlock transition. + //mTranslateKeyMap[SDLK_KP4] = KEY_PAD_LEFT; + //mTranslateKeyMap[SDLK_KP6] = KEY_PAD_RIGHT; + //mTranslateKeyMap[SDLK_KP8] = KEY_PAD_UP; + //mTranslateKeyMap[SDLK_KP2] = KEY_PAD_DOWN; + //mTranslateKeyMap[SDLK_KP_PERIOD] = KEY_DELETE; + //mTranslateKeyMap[SDLK_KP7] = KEY_HOME; + //mTranslateKeyMap[SDLK_KP1] = KEY_END; + //mTranslateKeyMap[SDLK_KP9] = KEY_PAGE_UP; + //mTranslateKeyMap[SDLK_KP3] = KEY_PAGE_DOWN; + //mTranslateKeyMap[SDLK_KP0] = KEY_INSERT; + + mTranslateKeyMap[SDLK_SPACE] = ' '; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_RETURN] = KEY_RETURN; + mTranslateKeyMap[SDLK_LEFT] = KEY_LEFT; + mTranslateKeyMap[SDLK_RIGHT] = KEY_RIGHT; + mTranslateKeyMap[SDLK_UP] = KEY_UP; + mTranslateKeyMap[SDLK_DOWN] = KEY_DOWN; + mTranslateKeyMap[SDLK_KP_ENTER] = KEY_RETURN; + mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; + mTranslateKeyMap[SDLK_BACKSPACE] = KEY_BACKSPACE; + mTranslateKeyMap[SDLK_DELETE] = KEY_DELETE; + mTranslateKeyMap[SDLK_LSHIFT] = KEY_SHIFT; + mTranslateKeyMap[SDLK_RSHIFT] = KEY_SHIFT; + mTranslateKeyMap[SDLK_LCTRL] = KEY_CONTROL; + mTranslateKeyMap[SDLK_RCTRL] = KEY_CONTROL; + mTranslateKeyMap[SDLK_LALT] = KEY_ALT; + mTranslateKeyMap[SDLK_RALT] = KEY_ALT; + mTranslateKeyMap[SDLK_HOME] = KEY_HOME; + mTranslateKeyMap[SDLK_END] = KEY_END; + mTranslateKeyMap[SDLK_PAGEUP] = KEY_PAGE_UP; + mTranslateKeyMap[SDLK_PAGEDOWN] = KEY_PAGE_DOWN; + mTranslateKeyMap[SDLK_MINUS] = KEY_HYPHEN; + mTranslateKeyMap[SDLK_EQUALS] = KEY_EQUALS; + mTranslateKeyMap[SDLK_KP_EQUALS] = KEY_EQUALS; + mTranslateKeyMap[SDLK_INSERT] = KEY_INSERT; + mTranslateKeyMap[SDLK_CAPSLOCK] = KEY_CAPSLOCK; + mTranslateKeyMap[SDLK_TAB] = KEY_TAB; + mTranslateKeyMap[SDLK_KP_PLUS] = KEY_ADD; + mTranslateKeyMap[SDLK_KP_MINUS] = KEY_SUBTRACT; + mTranslateKeyMap[SDLK_KP_MULTIPLY] = KEY_MULTIPLY; + mTranslateKeyMap[SDLK_KP_DIVIDE] = KEY_PAD_DIVIDE; + mTranslateKeyMap[SDLK_F1] = KEY_F1; + mTranslateKeyMap[SDLK_F2] = KEY_F2; + mTranslateKeyMap[SDLK_F3] = KEY_F3; + mTranslateKeyMap[SDLK_F4] = KEY_F4; + mTranslateKeyMap[SDLK_F5] = KEY_F5; + mTranslateKeyMap[SDLK_F6] = KEY_F6; + mTranslateKeyMap[SDLK_F7] = KEY_F7; + mTranslateKeyMap[SDLK_F8] = KEY_F8; + mTranslateKeyMap[SDLK_F9] = KEY_F9; + mTranslateKeyMap[SDLK_F10] = KEY_F10; + mTranslateKeyMap[SDLK_F11] = KEY_F11; + mTranslateKeyMap[SDLK_F12] = KEY_F12; + mTranslateKeyMap[SDLK_PLUS] = '='; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_COMMA] = ','; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_MINUS] = '-'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_PERIOD] = '.'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_BACKQUOTE] = '`'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_SLASH] = KEY_DIVIDE; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_SEMICOLON] = ';'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_QUOTE] = '\''; // Those are handled by SDL2 via text input, do not map them + + // Build inverse map + for (auto iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) + { + mInvTranslateKeyMap[iter->second] = iter->first; + } + + // numpad map + mTranslateNumpadMap[SDLK_KP_0] = KEY_PAD_INS; + mTranslateNumpadMap[SDLK_KP_1] = KEY_PAD_END; + mTranslateNumpadMap[SDLK_KP_2] = KEY_PAD_DOWN; + mTranslateNumpadMap[SDLK_KP_3] = KEY_PAD_PGDN; + mTranslateNumpadMap[SDLK_KP_4] = KEY_PAD_LEFT; + mTranslateNumpadMap[SDLK_KP_5] = KEY_PAD_CENTER; + mTranslateNumpadMap[SDLK_KP_6] = KEY_PAD_RIGHT; + mTranslateNumpadMap[SDLK_KP_7] = KEY_PAD_HOME; + mTranslateNumpadMap[SDLK_KP_8] = KEY_PAD_UP; + mTranslateNumpadMap[SDLK_KP_9] = KEY_PAD_PGUP; + mTranslateNumpadMap[SDLK_KP_PERIOD] = KEY_PAD_DEL; + + // build inverse numpad map + for (auto iter = mTranslateNumpadMap.begin(); + iter != mTranslateNumpadMap.end(); + iter++) + { + mInvTranslateNumpadMap[iter->second] = iter->first; + } +} + +void LLKeyboardSDL::resetMaskKeys() +{ + SDL_Keymod mask = SDL_GetModState(); + + // MBW -- XXX -- This mirrors the operation of the Windows version of resetMaskKeys(). + // It looks a bit suspicious, as it won't correct for keys that have been released. + // Is this the way it's supposed to work? + + if(mask & KMOD_SHIFT) + { + mKeyLevel[KEY_SHIFT] = TRUE; + } + + if(mask & KMOD_CTRL) + { + mKeyLevel[KEY_CONTROL] = TRUE; + } + + if(mask & KMOD_ALT) + { + mKeyLevel[KEY_ALT] = TRUE; + } +} + + +MASK LLKeyboardSDL::updateModifiers(const U32 mask) +{ + // translate the mask + MASK out_mask = MASK_NONE; + + if(mask & KMOD_SHIFT) + { + out_mask |= MASK_SHIFT; + } + + if(mask & KMOD_CTRL) + { + out_mask |= MASK_CONTROL; + } + + if(mask & KMOD_ALT) + { + out_mask |= MASK_ALT; + } + + return out_mask; +} + + +static U32 adjustNativekeyFromUnhandledMask(const U32 key, const U32 mask) +{ + // SDL doesn't automatically adjust the keysym according to + // whether NUMLOCK is engaged, so we massage the keysym manually. + U32 rtn = key; + if (!(mask & KMOD_NUM)) + { + switch (key) + { + case SDLK_KP_PERIOD: rtn = SDLK_DELETE; break; + case SDLK_KP_0: rtn = SDLK_INSERT; break; + case SDLK_KP_1: rtn = SDLK_END; break; + case SDLK_KP_2: rtn = SDLK_DOWN; break; + case SDLK_KP_3: rtn = SDLK_PAGEDOWN; break; + case SDLK_KP_4: rtn = SDLK_LEFT; break; + case SDLK_KP_6: rtn = SDLK_RIGHT; break; + case SDLK_KP_7: rtn = SDLK_HOME; break; + case SDLK_KP_8: rtn = SDLK_UP; break; + case SDLK_KP_9: rtn = SDLK_PAGEUP; break; + } + } + return rtn; +} + + +BOOL LLKeyboardSDL::handleKeyDown(const U32 key, const U32 mask) +{ + U32 adjusted_nativekey; + KEY translated_key = 0; + U32 translated_mask = MASK_NONE; + BOOL handled = FALSE; + + adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); + + translated_mask = updateModifiers(mask); + + if(translateNumpadKey(adjusted_nativekey, &translated_key)) + { + handled = handleTranslatedKeyDown(translated_key, translated_mask); + } + + return handled; +} + + +BOOL LLKeyboardSDL::handleKeyUp(const U32 key, const U32 mask) +{ + U32 adjusted_nativekey; + KEY translated_key = 0; + U32 translated_mask = MASK_NONE; + BOOL handled = FALSE; + + adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); + + translated_mask = updateModifiers(mask); + + if(translateNumpadKey(adjusted_nativekey, &translated_key)) + { + handled = handleTranslatedKeyUp(translated_key, translated_mask); + } + + return handled; +} + +MASK LLKeyboardSDL::currentMask(BOOL for_mouse_event) +{ + MASK result = MASK_NONE; + SDL_Keymod mask = SDL_GetModState(); + + if (mask & KMOD_SHIFT) + result |= MASK_SHIFT; + if (mask & KMOD_CTRL) + result |= MASK_CONTROL; + if (mask & KMOD_ALT) + result |= MASK_ALT; + + // For keyboard events, consider Meta keys equivalent to Control + if (!for_mouse_event) + { + if (mask & KMOD_GUI) + result |= MASK_CONTROL; + } + + return result; +} + +void LLKeyboardSDL::scanKeyboard() +{ + for (S32 key = 0; key < KEY_COUNT; key++) + { + // Generate callback if any event has occurred on this key this frame. + // Can't just test mKeyLevel, because this could be a slow frame and + // key might have gone down then up. JC + if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) + { + mCurScanKey = key; + mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); + } + } + + // Reset edges for next frame + for (S32 key = 0; key < KEY_COUNT; key++) + { + mKeyUp[key] = FALSE; + mKeyDown[key] = FALSE; + if (mKeyLevel[key]) + { + mKeyLevelFrameCount[key]++; + } + } +} + + +BOOL LLKeyboardSDL::translateNumpadKey( const U32 os_key, KEY *translated_key) +{ + return translateKey(os_key, translated_key); +} + +U16 LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key) +{ + return inverseTranslateKey(translated_key); +} + +enum class WindowsVK : U32 +{ + VK_UNKNOWN = 0, + VK_CANCEL = 0x03, + VK_BACK = 0x08, + VK_TAB = 0x09, + VK_CLEAR = 0x0C, + VK_RETURN = 0x0D, + VK_SHIFT = 0x10, + VK_CONTROL = 0x11, + VK_MENU = 0x12, + VK_PAUSE = 0x13, + VK_CAPITAL = 0x14, + VK_KANA = 0x15, + VK_HANGUL = 0x15, + VK_JUNJA = 0x17, + VK_FINAL = 0x18, + VK_HANJA = 0x19, + VK_KANJI = 0x19, + VK_ESCAPE = 0x1B, + VK_CONVERT = 0x1C, + VK_NONCONVERT = 0x1D, + VK_ACCEPT = 0x1E, + VK_MODECHANGE = 0x1F, + VK_SPACE = 0x20, + VK_PRIOR = 0x21, + VK_NEXT = 0x22, + VK_END = 0x23, + VK_HOME = 0x24, + VK_LEFT = 0x25, + VK_UP = 0x26, + VK_RIGHT = 0x27, + VK_DOWN = 0x28, + VK_SELECT = 0x29, + VK_PRINT = 0x2A, + VK_EXECUTE = 0x2B, + VK_SNAPSHOT = 0x2C, + VK_INSERT = 0x2D, + VK_DELETE = 0x2E, + VK_HELP = 0x2F, + VK_0 = 0x30, + VK_1 = 0x31, + VK_2 = 0x32, + VK_3 = 0x33, + VK_4 = 0x34, + VK_5 = 0x35, + VK_6 = 0x36, + VK_7 = 0x37, + VK_8 = 0x38, + VK_9 = 0x39, + VK_A = 0x41, + VK_B = 0x42, + VK_C = 0x43, + VK_D = 0x44, + VK_E = 0x45, + VK_F = 0x46, + VK_G = 0x47, + VK_H = 0x48, + VK_I = 0x49, + VK_J = 0x4A, + VK_K = 0x4B, + VK_L = 0x4C, + VK_M = 0x4D, + VK_N = 0x4E, + VK_O = 0x4F, + VK_P = 0x50, + VK_Q = 0x51, + VK_R = 0x52, + VK_S = 0x53, + VK_T = 0x54, + VK_U = 0x55, + VK_V = 0x56, + VK_W = 0x57, + VK_X = 0x58, + VK_Y = 0x59, + VK_Z = 0x5A, + VK_LWIN = 0x5B, + VK_RWIN = 0x5C, + VK_APPS = 0x5D, + VK_SLEEP = 0x5F, + VK_NUMPAD0 = 0x60, + VK_NUMPAD1 = 0x61, + VK_NUMPAD2 = 0x62, + VK_NUMPAD3 = 0x63, + VK_NUMPAD4 = 0x64, + VK_NUMPAD5 = 0x65, + VK_NUMPAD6 = 0x66, + VK_NUMPAD7 = 0x67, + VK_NUMPAD8 = 0x68, + VK_NUMPAD9 = 0x69, + VK_MULTIPLY = 0x6A, + VK_ADD = 0x6B, + VK_SEPARATOR = 0x6C, + VK_SUBTRACT = 0x6D, + VK_DECIMAL = 0x6E, + VK_DIVIDE = 0x6F, + VK_F1 = 0x70, + VK_F2 = 0x71, + VK_F3 = 0x72, + VK_F4 = 0x73, + VK_F5 = 0x74, + VK_F6 = 0x75, + VK_F7 = 0x76, + VK_F8 = 0x77, + VK_F9 = 0x78, + VK_F10 = 0x79, + VK_F11 = 0x7A, + VK_F12 = 0x7B, + VK_F13 = 0x7C, + VK_F14 = 0x7D, + VK_F15 = 0x7E, + VK_F16 = 0x7F, + VK_F17 = 0x80, + VK_F18 = 0x81, + VK_F19 = 0x82, + VK_F20 = 0x83, + VK_F21 = 0x84, + VK_F22 = 0x85, + VK_F23 = 0x86, + VK_F24 = 0x87, + VK_NUMLOCK = 0x90, + VK_SCROLL = 0x91, + VK_LSHIFT = 0xA0, + VK_RSHIFT = 0xA1, + VK_LCONTROL = 0xA2, + VK_RCONTROL = 0xA3, + VK_LMENU = 0xA4, + VK_RMENU = 0xA5, + VK_BROWSER_BACK = 0xA6, + VK_BROWSER_FORWARD = 0xA7, + VK_BROWSER_REFRESH = 0xA8, + VK_BROWSER_STOP = 0xA9, + VK_BROWSER_SEARCH = 0xAA, + VK_BROWSER_FAVORITES = 0xAB, + VK_BROWSER_HOME = 0xAC, + VK_VOLUME_MUTE = 0xAD, + VK_VOLUME_DOWN = 0xAE, + VK_VOLUME_UP = 0xAF, + VK_MEDIA_NEXT_TRACK = 0xB0, + VK_MEDIA_PREV_TRACK = 0xB1, + VK_MEDIA_STOP = 0xB2, + VK_MEDIA_PLAY_PAUSE = 0xB3, + VK_MEDIA_LAUNCH_MAIL = 0xB4, + VK_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5, + VK_MEDIA_LAUNCH_APP1 = 0xB6, + VK_MEDIA_LAUNCH_APP2 = 0xB7, + VK_OEM_1 = 0xBA, + VK_OEM_PLUS = 0xBB, + VK_OEM_COMMA = 0xBC, + VK_OEM_MINUS = 0xBD, + VK_OEM_PERIOD = 0xBE, + VK_OEM_2 = 0xBF, + VK_OEM_3 = 0xC0, + VK_OEM_4 = 0xDB, + VK_OEM_5 = 0xDC, + VK_OEM_6 = 0xDD, + VK_OEM_7 = 0xDE, + VK_OEM_8 = 0xDF, + VK_OEM_102 = 0xE2, + VK_PROCESSKEY = 0xE5, + VK_PACKET = 0xE7, + VK_ATTN = 0xF6, + VK_CRSEL = 0xF7, + VK_EXSEL = 0xF8, + VK_EREOF = 0xF9, + VK_PLAY = 0xFA, + VK_ZOOM = 0xFB, + VK_NONAME = 0xFC, + VK_PA1 = 0xFD, + VK_OEM_CLEAR = 0xFE, +}; + +std::map< U32, U32 > mSDL2_to_Win; +std::set< U32 > mIgnoreSDL2Keys; + +U32 LLKeyboardSDL::mapSDL2toWin( U32 aSymbol ) +{ + // Map SDLK_ virtual keys to Windows VK_ virtual keys. + // Text is handled via unicode input (SDL_TEXTINPUT event) and does not need to be translated into VK_ values as those match already. + if( mSDL2_to_Win.empty() ) + { + + mSDL2_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::VK_BACK; + mSDL2_to_Win[ SDLK_TAB ] = (U32)WindowsVK::VK_TAB; + mSDL2_to_Win[ 12 ] = (U32)WindowsVK::VK_CLEAR; + mSDL2_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::VK_RETURN; + mSDL2_to_Win[ 19 ] = (U32)WindowsVK::VK_PAUSE; + mSDL2_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::VK_ESCAPE; + mSDL2_to_Win[ SDLK_SPACE ] = (U32)WindowsVK::VK_SPACE; + mSDL2_to_Win[ SDLK_QUOTE ] = (U32)WindowsVK::VK_OEM_7; + mSDL2_to_Win[ SDLK_COMMA ] = (U32)WindowsVK::VK_OEM_COMMA; + mSDL2_to_Win[ SDLK_MINUS ] = (U32)WindowsVK::VK_OEM_MINUS; + mSDL2_to_Win[ SDLK_PERIOD ] = (U32)WindowsVK::VK_OEM_PERIOD; + mSDL2_to_Win[ SDLK_SLASH ] = (U32)WindowsVK::VK_OEM_2; + + mSDL2_to_Win[ SDLK_0 ] = (U32)WindowsVK::VK_0; + mSDL2_to_Win[ SDLK_1 ] = (U32)WindowsVK::VK_1; + mSDL2_to_Win[ SDLK_2 ] = (U32)WindowsVK::VK_2; + mSDL2_to_Win[ SDLK_3 ] = (U32)WindowsVK::VK_3; + mSDL2_to_Win[ SDLK_4 ] = (U32)WindowsVK::VK_4; + mSDL2_to_Win[ SDLK_5 ] = (U32)WindowsVK::VK_5; + mSDL2_to_Win[ SDLK_6 ] = (U32)WindowsVK::VK_6; + mSDL2_to_Win[ SDLK_7 ] = (U32)WindowsVK::VK_7; + mSDL2_to_Win[ SDLK_8 ] = (U32)WindowsVK::VK_8; + mSDL2_to_Win[ SDLK_9 ] = (U32)WindowsVK::VK_9; + + mSDL2_to_Win[ SDLK_SEMICOLON ] = (U32)WindowsVK::VK_OEM_1; + mSDL2_to_Win[ SDLK_LESS ] = (U32)WindowsVK::VK_OEM_102; + mSDL2_to_Win[ SDLK_EQUALS ] = (U32)WindowsVK::VK_OEM_PLUS; + mSDL2_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::VK_OEM_PLUS; + + mSDL2_to_Win[ SDLK_LEFTBRACKET ] = (U32)WindowsVK::VK_OEM_4; + mSDL2_to_Win[ SDLK_BACKSLASH ] = (U32)WindowsVK::VK_OEM_5; + mSDL2_to_Win[ SDLK_RIGHTBRACKET ] = (U32)WindowsVK::VK_OEM_6; + mSDL2_to_Win[ SDLK_BACKQUOTE ] = (U32)WindowsVK::VK_OEM_8; + + mSDL2_to_Win[ SDLK_a ] = (U32)WindowsVK::VK_A; + mSDL2_to_Win[ SDLK_b ] = (U32)WindowsVK::VK_B; + mSDL2_to_Win[ SDLK_c ] = (U32)WindowsVK::VK_C; + mSDL2_to_Win[ SDLK_d ] = (U32)WindowsVK::VK_D; + mSDL2_to_Win[ SDLK_e ] = (U32)WindowsVK::VK_E; + mSDL2_to_Win[ SDLK_f ] = (U32)WindowsVK::VK_F; + mSDL2_to_Win[ SDLK_g ] = (U32)WindowsVK::VK_G; + mSDL2_to_Win[ SDLK_h ] = (U32)WindowsVK::VK_H; + mSDL2_to_Win[ SDLK_i ] = (U32)WindowsVK::VK_I; + mSDL2_to_Win[ SDLK_j ] = (U32)WindowsVK::VK_J; + mSDL2_to_Win[ SDLK_k ] = (U32)WindowsVK::VK_K; + mSDL2_to_Win[ SDLK_l ] = (U32)WindowsVK::VK_L; + mSDL2_to_Win[ SDLK_m ] = (U32)WindowsVK::VK_M; + mSDL2_to_Win[ SDLK_n ] = (U32)WindowsVK::VK_N; + mSDL2_to_Win[ SDLK_o ] = (U32)WindowsVK::VK_O; + mSDL2_to_Win[ SDLK_p ] = (U32)WindowsVK::VK_P; + mSDL2_to_Win[ SDLK_q ] = (U32)WindowsVK::VK_Q; + mSDL2_to_Win[ SDLK_r ] = (U32)WindowsVK::VK_R; + mSDL2_to_Win[ SDLK_s ] = (U32)WindowsVK::VK_S; + mSDL2_to_Win[ SDLK_t ] = (U32)WindowsVK::VK_T; + mSDL2_to_Win[ SDLK_u ] = (U32)WindowsVK::VK_U; + mSDL2_to_Win[ SDLK_v ] = (U32)WindowsVK::VK_V; + mSDL2_to_Win[ SDLK_w ] = (U32)WindowsVK::VK_W; + mSDL2_to_Win[ SDLK_x ] = (U32)WindowsVK::VK_X; + mSDL2_to_Win[ SDLK_y ] = (U32)WindowsVK::VK_Y; + mSDL2_to_Win[ SDLK_z ] = (U32)WindowsVK::VK_Z; + + mSDL2_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::VK_DELETE; + + + mSDL2_to_Win[ SDLK_NUMLOCKCLEAR ] = (U32)WindowsVK::VK_NUMLOCK; + mSDL2_to_Win[ SDLK_SCROLLLOCK ] = (U32)WindowsVK::VK_SCROLL; + + mSDL2_to_Win[ SDLK_HELP ] = (U32)WindowsVK::VK_HELP; + mSDL2_to_Win[ SDLK_PRINTSCREEN ] = (U32)WindowsVK::VK_SNAPSHOT; + mSDL2_to_Win[ SDLK_CANCEL ] = (U32)WindowsVK::VK_CANCEL; + mSDL2_to_Win[ SDLK_APPLICATION ] = (U32)WindowsVK::VK_APPS; + + mSDL2_to_Win[ SDLK_UNKNOWN ] = (U32)WindowsVK::VK_UNKNOWN; + mSDL2_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::VK_BACK; + mSDL2_to_Win[ SDLK_TAB ] = (U32)WindowsVK::VK_TAB; + mSDL2_to_Win[ SDLK_CLEAR ] = (U32)WindowsVK::VK_CLEAR; + mSDL2_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::VK_RETURN; + mSDL2_to_Win[ SDLK_PAUSE ] = (U32)WindowsVK::VK_PAUSE; + mSDL2_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::VK_ESCAPE; + mSDL2_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::VK_DELETE; + + mSDL2_to_Win[ SDLK_KP_PERIOD ] = (U32)WindowsVK::VK_OEM_PERIOD; // VK_DECIMAL? + mSDL2_to_Win[ SDLK_KP_DIVIDE ] = (U32)WindowsVK::VK_DIVIDE; + mSDL2_to_Win[ SDLK_KP_MULTIPLY] = (U32)WindowsVK::VK_MULTIPLY; + mSDL2_to_Win[ SDLK_KP_MINUS ] = (U32)WindowsVK::VK_OEM_MINUS; // VK_SUBSTRACT? + mSDL2_to_Win[ SDLK_KP_PLUS ] = (U32)WindowsVK::VK_OEM_PLUS; // VK_ADD? + mSDL2_to_Win[ SDLK_KP_ENTER ] = (U32)WindowsVK::VK_RETURN; + mSDL2_to_Win[ SDLK_KP_0 ] = (U32)WindowsVK::VK_NUMPAD0; + mSDL2_to_Win[ SDLK_KP_1 ] = (U32)WindowsVK::VK_NUMPAD1; + mSDL2_to_Win[ SDLK_KP_2 ] = (U32)WindowsVK::VK_NUMPAD2; + mSDL2_to_Win[ SDLK_KP_3 ] = (U32)WindowsVK::VK_NUMPAD3; + mSDL2_to_Win[ SDLK_KP_4 ] = (U32)WindowsVK::VK_NUMPAD4; + mSDL2_to_Win[ SDLK_KP_5 ] = (U32)WindowsVK::VK_NUMPAD5; + mSDL2_to_Win[ SDLK_KP_6 ] = (U32)WindowsVK::VK_NUMPAD6; + mSDL2_to_Win[ SDLK_KP_7 ] = (U32)WindowsVK::VK_NUMPAD7; + mSDL2_to_Win[ SDLK_KP_8 ] = (U32)WindowsVK::VK_NUMPAD8; + mSDL2_to_Win[ SDLK_KP_9 ] = (U32)WindowsVK::VK_NUMPAD9; + + // ? + + mSDL2_to_Win[ SDLK_UP ] = (U32)WindowsVK::VK_UP; + mSDL2_to_Win[ SDLK_DOWN ] = (U32)WindowsVK::VK_DOWN; + mSDL2_to_Win[ SDLK_RIGHT ] = (U32)WindowsVK::VK_RIGHT; + mSDL2_to_Win[ SDLK_LEFT ] = (U32)WindowsVK::VK_LEFT; + mSDL2_to_Win[ SDLK_INSERT ] = (U32)WindowsVK::VK_INSERT; + mSDL2_to_Win[ SDLK_HOME ] = (U32)WindowsVK::VK_HOME; + mSDL2_to_Win[ SDLK_END ] = (U32)WindowsVK::VK_END; + mSDL2_to_Win[ SDLK_PAGEUP ] = (U32)WindowsVK::VK_PRIOR; + mSDL2_to_Win[ SDLK_PAGEDOWN ] = (U32)WindowsVK::VK_NEXT; + mSDL2_to_Win[ SDLK_F1 ] = (U32)WindowsVK::VK_F1; + mSDL2_to_Win[ SDLK_F2 ] = (U32)WindowsVK::VK_F2; + mSDL2_to_Win[ SDLK_F3 ] = (U32)WindowsVK::VK_F3; + mSDL2_to_Win[ SDLK_F4 ] = (U32)WindowsVK::VK_F4; + mSDL2_to_Win[ SDLK_F5 ] = (U32)WindowsVK::VK_F5; + mSDL2_to_Win[ SDLK_F6 ] = (U32)WindowsVK::VK_F6; + mSDL2_to_Win[ SDLK_F7 ] = (U32)WindowsVK::VK_F7; + mSDL2_to_Win[ SDLK_F8 ] = (U32)WindowsVK::VK_F8; + mSDL2_to_Win[ SDLK_F9 ] = (U32)WindowsVK::VK_F9; + mSDL2_to_Win[ SDLK_F10 ] = (U32)WindowsVK::VK_F10; + mSDL2_to_Win[ SDLK_F11 ] = (U32)WindowsVK::VK_F11; + mSDL2_to_Win[ SDLK_F12 ] = (U32)WindowsVK::VK_F12; + mSDL2_to_Win[ SDLK_F13 ] = (U32)WindowsVK::VK_F13; + mSDL2_to_Win[ SDLK_F14 ] = (U32)WindowsVK::VK_F14; + mSDL2_to_Win[ SDLK_F15 ] = (U32)WindowsVK::VK_F15; + mSDL2_to_Win[ SDLK_CAPSLOCK ] = (U32)WindowsVK::VK_CAPITAL; + mSDL2_to_Win[ SDLK_RSHIFT ] = (U32)WindowsVK::VK_SHIFT; + mSDL2_to_Win[ SDLK_LSHIFT ] = (U32)WindowsVK::VK_SHIFT; + mSDL2_to_Win[ SDLK_RCTRL ] = (U32)WindowsVK::VK_CONTROL; + mSDL2_to_Win[ SDLK_LCTRL ] = (U32)WindowsVK::VK_CONTROL; + mSDL2_to_Win[ SDLK_RALT ] = (U32)WindowsVK::VK_MENU; + mSDL2_to_Win[ SDLK_LALT ] = (U32)WindowsVK::VK_MENU; + + mSDL2_to_Win[ SDLK_MENU ] = (U32)WindowsVK::VK_MENU; + + // VK_MODECHANGE ? + // mSDL2_to_Win[ SDLK_MODE ] = (U32)WindowsVK::VK_MODE; + + // ? + // mSDL2_to_Win[ SDLK_SYSREQ ] = (U32)WindowsVK::VK_SYSREQ; + // mSDL2_to_Win[ SDLK_POWER ] = (U32)WindowsVK::VK_POWER; + // mSDL2_to_Win[ SDLK_UNDO ] = (U32)WindowsVK::VK_UNDO; + // mSDL2_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::VK_EQUALS; + // mSDL2_to_Win[ 311 ] = (U32)WindowsVK::VK_LWIN; + // mSDL2_to_Win[ 312 ] = (U32)WindowsVK::VK_RWIN; + // mSDL2_to_Win[ SDLK_COLON ] = ? + } + + auto itr = mSDL2_to_Win.find( aSymbol ); + if( itr != mSDL2_to_Win.end() ) + return itr->second; + + return aSymbol; +} + +#endif + diff --git a/indra/llwindow/llkeyboardsdl2.h b/indra/llwindow/llkeyboardsdl2.h new file mode 100644 index 0000000000..01ded5c146 --- /dev/null +++ b/indra/llwindow/llkeyboardsdl2.h @@ -0,0 +1,33 @@ + +#ifndef LL_LLKEYBOARDSDL2_H +#define LL_LLKEYBOARDSDL2_H + +#include "llkeyboard.h" +#include "SDL2/SDL.h" + +class LLKeyboardSDL : public LLKeyboard +{ +public: + LLKeyboardSDL(); + /*virtual*/ ~LLKeyboardSDL() {}; + + /*virtual*/ BOOL handleKeyUp(const U32 key, MASK mask); + /*virtual*/ BOOL handleKeyDown(const U32 key, MASK mask); + /*virtual*/ void resetMaskKeys(); + /*virtual*/ MASK currentMask(BOOL for_mouse_event); + /*virtual*/ void scanKeyboard(); + +protected: + MASK updateModifiers(const U32 mask); + void setModifierKeyLevel( KEY key, BOOL new_state ); + BOOL translateNumpadKey( const U32 os_key, KEY *translated_key ); + U16 inverseTranslateNumpadKey(const KEY translated_key); +private: + std::map mTranslateNumpadMap; // special map for translating OS keys to numpad keys + std::map mInvTranslateNumpadMap; // inverse of the above + +public: + static U32 mapSDL2toWin( U32 ); +}; + +#endif diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index a0ca9839a5..c2d49fd251 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -24,6 +24,10 @@ * $/LicenseInfo$ */ +#ifdef LL_SDL2 +#include "llwindowsdl2.h" +#else + #ifndef LL_LLWINDOWSDL_H #define LL_LLWINDOWSDL_H @@ -255,3 +259,4 @@ public: S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type); #endif //LL_LLWINDOWSDL_H +#endif \ No newline at end of file diff --git a/indra/llwindow/llwindowsdl2.cpp b/indra/llwindow/llwindowsdl2.cpp new file mode 100644 index 0000000000..b5e350f863 --- /dev/null +++ b/indra/llwindow/llwindowsdl2.cpp @@ -0,0 +1,2563 @@ +/** + * @file llwindowsdl.cpp + * @brief SDL implementation of LLWindow class + * @author This module has many fathers, and it shows. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#if LL_SDL2 + +#include "linden_common.h" + +#include "llwindowsdl.h" + +#include "llwindowcallbacks.h" +#include "llkeyboardsdl.h" + +#include "llerror.h" +#include "llgl.h" +#include "llstring.h" +#include "lldir.h" +#include "llfindlocale.h" + +#ifdef LL_GLIB +#include +#endif + +extern "C" { +# include "fontconfig/fontconfig.h" +} + +#if LL_LINUX +// not necessarily available on random SDL platforms, so #if LL_LINUX +// for execv(), waitpid(), fork() +# include +# include +# include +# include +#endif // LL_LINUX + +extern BOOL gDebugWindowProc; + +const S32 MAX_NUM_RESOLUTIONS = 200; + +// static variable for ATI mouse cursor crash work-around: +static bool ATIbug = false; + +// +// LLWindowSDL +// + +#if LL_X11 +# include +#endif //LL_X11 + +// TOFU HACK -- (*exactly* the same hack as LLWindowMacOSX for a similar +// set of reasons): Stash a pointer to the LLWindowSDL object here and +// maintain in the constructor and destructor. This assumes that there will +// be only one object of this class at any time. Currently this is true. +static LLWindowSDL *gWindowImplementation = NULL; + + +void maybe_lock_display(void) +{ + if (gWindowImplementation && gWindowImplementation->Lock_Display) { + gWindowImplementation->Lock_Display(); + } +} + + +void maybe_unlock_display(void) +{ + if (gWindowImplementation && gWindowImplementation->Unlock_Display) { + gWindowImplementation->Unlock_Display(); + } +} + + +#if LL_X11 +// static +Window LLWindowSDL::get_SDL_XWindowID(void) +{ + if (gWindowImplementation) { + return gWindowImplementation->mSDL_XWindowID; + } + return None; +} + +//static +Display* LLWindowSDL::get_SDL_Display(void) +{ + if (gWindowImplementation) { + return gWindowImplementation->mSDL_Display; + } + return NULL; +} +#endif // LL_X11 + +#if LL_X11 + +// Clipboard handing via native X11, base on the implementation in Cool VL by Henri Beauchamp + +namespace +{ + std::array gSupportedAtoms; + + Atom XA_CLIPBOARD; + Atom XA_TARGETS; + Atom PVT_PASTE_BUFFER; + long const MAX_PASTE_BUFFER_SIZE = 16383; + + void filterSelectionRequest( XEvent aEvent ) + { + auto *display = LLWindowSDL::getSDLDisplay(); + auto &request = aEvent.xselectionrequest; + + XSelectionEvent reply { SelectionNotify, aEvent.xany.serial, aEvent.xany.send_event, display, + request.requestor, request.selection, request.target, + request.property,request.time }; + + if (request.target == XA_TARGETS) + { + XChangeProperty(display, request.requestor, request.property, + XA_ATOM, 32, PropModeReplace, + (unsigned char *) &gSupportedAtoms.front(), gSupportedAtoms.size()); + } + else if (std::find(gSupportedAtoms.begin(), gSupportedAtoms.end(), request.target) != + gSupportedAtoms.end()) + { + std::string utf8; + if (request.selection == XA_PRIMARY) + utf8 = wstring_to_utf8str(gWindowImplementation->getPrimaryText()); + else + utf8 = wstring_to_utf8str(gWindowImplementation->getSecondaryText()); + + XChangeProperty(display, request.requestor, request.property, + request.target, 8, PropModeReplace, + (unsigned char *) utf8.c_str(), utf8.length()); + } + else if (request.selection == XA_CLIPBOARD) + { + // Did not have what they wanted, so no property set + reply.property = None; + } + else + return; + + XSendEvent(request.display, request.requestor, False, NoEventMask, (XEvent *) &reply); + XSync(display, False); + } + + void filterSelectionClearRequest( XEvent aEvent ) + { + auto &request = aEvent.xselectionrequest; + if (request.selection == XA_PRIMARY) + gWindowImplementation->clearPrimaryText(); + else if (request.selection == XA_CLIPBOARD) + gWindowImplementation->clearSecondaryText(); + } + + int x11_clipboard_filter(void*, SDL_Event *evt) + { + Display *display = LLWindowSDL::getSDLDisplay(); + if (!display) + return 1; + + if (evt->type != SDL_SYSWMEVENT) + return 1; + + auto xevent = evt->syswm.msg->msg.x11.event; + + if (xevent.type == SelectionRequest) + filterSelectionRequest( xevent ); + else if (xevent.type == SelectionClear) + filterSelectionClearRequest( xevent ); + return 1; + } + + bool grab_property(Display* display, Window window, Atom selection, Atom target) + { + if( !display ) + return false; + + maybe_lock_display(); + + XDeleteProperty(display, window, PVT_PASTE_BUFFER); + XFlush(display); + + XConvertSelection(display, selection, target, PVT_PASTE_BUFFER, window, CurrentTime); + + // Unlock the connection so that the SDL event loop may function + maybe_unlock_display(); + + const auto start{ SDL_GetTicks() }; + const auto end{ start + 1000 }; + + XEvent xevent {}; + bool response = false; + + do + { + SDL_Event event {}; + + // Wait for an event + SDL_WaitEvent(&event); + + // If the event is a window manager event + if (event.type == SDL_SYSWMEVENT) + { + xevent = event.syswm.msg->msg.x11.event; + + if (xevent.type == SelectionNotify && xevent.xselection.requestor == window) + response = true; + } + } while (!response && SDL_GetTicks() < end ); + + return response && xevent.xselection.property != None; + } +} + +void LLWindowSDL::initialiseX11Clipboard() +{ + if (!mSDL_Display) + return; + + SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); + SDL_SetEventFilter(x11_clipboard_filter, nullptr); + + maybe_lock_display(); + + XA_CLIPBOARD = XInternAtom(mSDL_Display, "CLIPBOARD", False); + + gSupportedAtoms[0] = XInternAtom(mSDL_Display, "UTF8_STRING", False); + gSupportedAtoms[1] = XInternAtom(mSDL_Display, "COMPOUND_TEXT", False); + gSupportedAtoms[2] = XA_STRING; + + // TARGETS atom + XA_TARGETS = XInternAtom(mSDL_Display, "TARGETS", False); + + // SL_PASTE_BUFFER atom + PVT_PASTE_BUFFER = XInternAtom(mSDL_Display, "FS_PASTE_BUFFER", False); + + maybe_unlock_display(); +} + +bool LLWindowSDL::getSelectionText( Atom aSelection, Atom aType, LLWString &text ) +{ + if( !mSDL_Display ) + return false; + + if( !grab_property(mSDL_Display, mSDL_XWindowID, aSelection,aType ) ) + return false; + + maybe_lock_display(); + + Atom type; + int format{}; + unsigned long len{},remaining {}; + unsigned char* data = nullptr; + int res = XGetWindowProperty(mSDL_Display, mSDL_XWindowID, + PVT_PASTE_BUFFER, 0, MAX_PASTE_BUFFER_SIZE, False, + AnyPropertyType, &type, &format, &len, + &remaining, &data); + if (data && len) + { + text = LLWString( + utf8str_to_wstring(reinterpret_cast< char const *>( data ) ) + ); + XFree(data); + } + + maybe_unlock_display(); + return res == Success; +} + +bool LLWindowSDL::getSelectionText(Atom selection, LLWString& text) +{ + if (!mSDL_Display) + return false; + + maybe_lock_display(); + + Window owner = XGetSelectionOwner(mSDL_Display, selection); + if (owner == None) + { + if (selection == XA_PRIMARY) + { + owner = DefaultRootWindow(mSDL_Display); + selection = XA_CUT_BUFFER0; + } + else + { + maybe_unlock_display(); + return false; + } + } + + maybe_unlock_display(); + + for( Atom atom : gSupportedAtoms ) + { + if(getSelectionText(selection, atom, text ) ) + return true; + } + + return false; +} + +bool LLWindowSDL::setSelectionText(Atom selection, const LLWString& text) +{ + maybe_lock_display(); + + if (selection == XA_PRIMARY) + { + std::string utf8 = wstring_to_utf8str(text); + XStoreBytes(mSDL_Display, utf8.c_str(), utf8.length() + 1); + mPrimaryClipboard = text; + } + else + mSecondaryClipboard = text; + + XSetSelectionOwner(mSDL_Display, selection, mSDL_XWindowID, CurrentTime); + + auto owner = XGetSelectionOwner(mSDL_Display, selection); + + maybe_unlock_display(); + + return owner == mSDL_XWindowID; +} + +Display* LLWindowSDL::getSDLDisplay() +{ + if (gWindowImplementation) + return gWindowImplementation->mSDL_Display; + return nullptr; +} + +#endif + + +LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, + const std::string& title, S32 x, S32 y, S32 width, + S32 height, U32 flags, + BOOL fullscreen, BOOL clearBg, + BOOL disable_vsync, BOOL use_gl, + // Legacy cursor setting from main program + //BOOL ignore_pixel_depth, U32 fsaa_samples,) + BOOL ignore_pixel_depth, U32 fsaa_samples, BOOL useLegacyCursors) + : LLWindow(callbacks, fullscreen, flags), + Lock_Display(NULL), + //Unlock_Display(NULL), mGamma(1.0f) + Unlock_Display(NULL), mGamma(1.0f), + mUseLegacyCursors(useLegacyCursors) // +{ + // Initialize the keyboard + gKeyboard = new LLKeyboardSDL(); + gKeyboard->setCallbacks(callbacks); + // Note that we can't set up key-repeat until after SDL has init'd video + + // Ignore use_gl for now, only used for drones on PC + mWindow = NULL; + mContext = {}; + mNeedsResize = FALSE; + mOverrideAspectRatio = 0.f; + mGrabbyKeyFlags = 0; + mReallyCapturedCount = 0; + mHaveInputFocus = -1; + mIsMinimized = -1; + mFSAASamples = fsaa_samples; + +#if LL_X11 + mSDL_XWindowID = None; + mSDL_Display = NULL; +#endif // LL_X11 + + // Assume 4:3 aspect ratio until we know better + mOriginalAspectRatio = 1024.0 / 768.0; + + if (title.empty()) + mWindowTitle = "SDL Window"; // *FIX: (?) + else + mWindowTitle = title; + + // Create the GL context and set it up for windowed or fullscreen, as appropriate. + if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) + { + gGLManager.initGL(); + + //start with arrow cursor + initCursors(useLegacyCursors); // Legacy cursor setting from main program + setCursor( UI_CURSOR_ARROW ); + } + + stop_glerror(); + + // Stash an object pointer for OSMessageBox() + gWindowImplementation = this; + +#if LL_X11 + mFlashing = FALSE; + initialiseX11Clipboard(); +#endif // LL_X11 + + mKeyVirtualKey = 0; + mKeyModifiers = KMOD_NONE; +} + +static SDL_Surface *Load_BMP_Resource(const char *basename) +{ + const int PATH_BUFFER_SIZE=1000; + char path_buffer[PATH_BUFFER_SIZE]; /* Flawfinder: ignore */ + + // Figure out where our BMP is living on the disk + snprintf(path_buffer, PATH_BUFFER_SIZE-1, "%s%sres-sdl%s%s", + gDirUtilp->getAppRODataDir().c_str(), + gDirUtilp->getDirDelimiter().c_str(), + gDirUtilp->getDirDelimiter().c_str(), + basename); + path_buffer[PATH_BUFFER_SIZE-1] = '\0'; + + return SDL_LoadBMP(path_buffer); +} + +#if LL_X11 +// This is an XFree86/XOrg-specific hack for detecting the amount of Video RAM +// on this machine. It works by searching /var/log/var/log/Xorg.?.log or +// /var/log/XFree86.?.log for a ': (VideoRAM ?|Memory): (%d+) kB' regex, where +// '?' is the X11 display number derived from $DISPLAY +static int x11_detect_VRAM_kb_fp(FILE *fp, const char *prefix_str) +{ + const int line_buf_size = 1000; + char line_buf[line_buf_size]; + while (fgets(line_buf, line_buf_size, fp)) + { + //LL_DEBUGS() << "XLOG: " << line_buf << LL_ENDL; + + // Why the ad-hoc parser instead of using a regex? Our + // favourite regex implementation - libboost_regex - is + // quite a heavy and troublesome dependency for the client, so + // it seems a shame to introduce it for such a simple task. + // *FIXME: libboost_regex is a dependency now anyway, so we may + // as well use it instead of this hand-rolled nonsense. + const char *part1_template = prefix_str; + const char part2_template[] = " kB"; + char *part1 = strstr(line_buf, part1_template); + if (part1) // found start of matching line + { + part1 = &part1[strlen(part1_template)]; // -> after + char *part2 = strstr(part1, part2_template); + if (part2) // found end of matching line + { + // now everything between part1 and part2 is + // supposed to be numeric, describing the + // number of kB of Video RAM supported + int rtn = 0; + for (; part1 < part2; ++part1) + { + if (*part1 < '0' || *part1 > '9') + { + // unexpected char, abort parse + rtn = 0; + break; + } + rtn *= 10; + rtn += (*part1) - '0'; + } + if (rtn > 0) + { + // got the kB number. return it now. + return rtn; + } + } + } + } + return 0; // 'could not detect' +} + +static int x11_detect_VRAM_kb() +{ + std::string x_log_location("/var/log/"); + std::string fname; + int rtn = 0; // 'could not detect' + int display_num = 0; + FILE *fp; + char *display_env = getenv("DISPLAY"); // e.g. :0 or :0.0 or :1.0 etc + // parse DISPLAY number so we can go grab the right log file + if (display_env[0] == ':' && + display_env[1] >= '0' && display_env[1] <= '9') + { + display_num = display_env[1] - '0'; + } + + // *TODO: we could be smarter and see which of Xorg/XFree86 has the + // freshest time-stamp. + + // Try Xorg log first + fname = x_log_location; + fname += "Xorg."; + fname += ('0' + display_num); + fname += ".log"; + fp = fopen(fname.c_str(), "r"); + if (fp) + { + LL_INFOS() << "Looking in " << fname + << " for VRAM info..." << LL_ENDL; + rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); + fclose(fp); + if (0 == rtn) + { + fp = fopen(fname.c_str(), "r"); + if (fp) + { + rtn = x11_detect_VRAM_kb_fp(fp, ": Video RAM: "); + fclose(fp); + if (0 == rtn) + { + fp = fopen(fname.c_str(), "r"); + if (fp) + { + rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); + fclose(fp); + } + } + } + } + } + else + { + LL_INFOS() << "Could not open " << fname + << " - skipped." << LL_ENDL; + // Try old XFree86 log otherwise + fname = x_log_location; + fname += "XFree86."; + fname += ('0' + display_num); + fname += ".log"; + fp = fopen(fname.c_str(), "r"); + if (fp) + { + LL_INFOS() << "Looking in " << fname + << " for VRAM info..." << LL_ENDL; + rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); + fclose(fp); + if (0 == rtn) + { + fp = fopen(fname.c_str(), "r"); + if (fp) + { + rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); + fclose(fp); + } + } + } + else + { + LL_INFOS() << "Could not open " << fname + << " - skipped." << LL_ENDL; + } + } + return rtn; +} +#endif // LL_X11 + +void LLWindowSDL::setTitle(const std::string &title) +{ + SDL_SetWindowTitle( mWindow, title.c_str() ); +} + +void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) +{ + LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; + + // If the requested width or height is 0, find the best default for the monitor. + if((width == 0) || (height == 0)) + { + // Scan through the list of modes, looking for one which has: + // height between 700 and 800 + // aspect ratio closest to the user's original mode + S32 resolutionCount = 0; + LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount); + + if(resolutionList != NULL) + { + F32 closestAspect = 0; + U32 closestHeight = 0; + U32 closestWidth = 0; + int i; + + LL_INFOS() << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << LL_ENDL; + + for(i=0; i < resolutionCount; i++) + { + F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight; + + LL_INFOS() << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << LL_ENDL; + + if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) && + (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio))) + { + LL_INFOS() << " (new closest mode) " << LL_ENDL; + + // This is the closest mode we've seen yet. + closestWidth = resolutionList[i].mWidth; + closestHeight = resolutionList[i].mHeight; + closestAspect = aspect; + } + } + + width = closestWidth; + height = closestHeight; + } + } + + if((width == 0) || (height == 0)) + { + // Mode search failed for some reason. Use the old-school default. + width = 1024; + height = 768; + } +} + +BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync) +{ + //bool glneedsinit = false; + + LL_INFOS() << "createContext, fullscreen=" << fullscreen << + " size=" << width << "x" << height << LL_ENDL; + + // captures don't survive contexts + mGrabbyKeyFlags = 0; + mReallyCapturedCount = 0; + + SDL_SetHint( SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0" ); + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO ) < 0 ) + { + LL_INFOS() << "sdl_init() failed! " << SDL_GetError() << LL_ENDL; + setupFailure("sdl_init() failure, window creation error", "error", OSMB_OK); + return false; + } + + SDL_version c_sdl_version; + SDL_VERSION(&c_sdl_version); + LL_INFOS() << "Compiled against SDL " + << int(c_sdl_version.major) << "." + << int(c_sdl_version.minor) << "." + << int(c_sdl_version.patch) << LL_ENDL; + SDL_version r_sdl_version; + SDL_GetVersion(&r_sdl_version); + LL_INFOS() << " Running against SDL " + << int(r_sdl_version.major) << "." + << int(r_sdl_version.minor) << "." + << int(r_sdl_version.patch) << LL_ENDL; + + if (width == 0) + width = 1024; + if (height == 0) + width = 768; + + mFullscreen = fullscreen; + + int sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; + + if( mFullscreen ) + { + sdlflags |= SDL_WINDOW_FULLSCREEN; + tryFindFullscreenSize( width, height ); + } + + mSDLFlags = sdlflags; + + GLint redBits{8}, greenBits{8}, blueBits{8}, alphaBits{8}; + + GLint depthBits{(bits <= 16) ? 16 : 24}, stencilBits{8}; + + if (getenv("LL_GL_NO_STENCIL")) + stencilBits = 0; + + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, alphaBits); + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, redBits); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, greenBits); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, blueBits); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthBits ); + + // We need stencil support for a few (minor) things. + if (stencilBits) + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencilBits); + // *FIX: try to toggle vsync here? + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + if (mFSAASamples > 0) + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mFSAASamples); + } + + mWindow = SDL_CreateWindow( mWindowTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, mSDLFlags ); + + if( mWindow ) + { + mContext = SDL_GL_CreateContext( mWindow ); + + if( mContext == 0 ) + { + LL_WARNS() << "Cannot create GL context " << SDL_GetError() << LL_ENDL; + setupFailure("GL Context creation error creation error", "Error", OSMB_OK); + return FALSE; + } + // SDL_GL_SetSwapInterval(1); + mSurface = SDL_GetWindowSurface( mWindow ); + } + + + if( mFullscreen ) + { + if (mSurface) + { + mFullscreen = TRUE; + mFullscreenWidth = mSurface->w; + mFullscreenHeight = mSurface->h; + mFullscreenBits = mSurface->format->BitsPerPixel; + mFullscreenRefresh = -1; + + LL_INFOS() << "Running at " << mFullscreenWidth + << "x" << mFullscreenHeight + << "x" << mFullscreenBits + << " @ " << mFullscreenRefresh + << LL_ENDL; + } + else + { + LL_WARNS() << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << LL_ENDL; + // No fullscreen support + mFullscreen = FALSE; + mFullscreenWidth = -1; + mFullscreenHeight = -1; + mFullscreenBits = -1; + mFullscreenRefresh = -1; + + std::string error = llformat("Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); + OSMessageBox(error, "Error", OSMB_OK); + return FALSE; + } + } + else + { + if (!mWindow) + { + LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL; + setupFailure("Window creation error", "Error", OSMB_OK); + return FALSE; + } + } + + // Set the application icon. + SDL_Surface *bmpsurface; + bmpsurface = Load_BMP_Resource("firestorm_icon.BMP"); + if (bmpsurface) + { + SDL_SetWindowIcon(mWindow, bmpsurface); + SDL_FreeSurface(bmpsurface); + bmpsurface = NULL; + } + + // Detect video memory size. +# if LL_X11 + gGLManager.mVRAM = x11_detect_VRAM_kb() / 1024; + if (gGLManager.mVRAM != 0) + { + LL_INFOS() << "X11 log-parser detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; + } else +# endif // LL_X11 + { + // fallback to letting SDL detect VRAM. + // note: I've not seen SDL's detection ever actually find + // VRAM != 0, but if SDL *does* detect it then that's a bonus. + gGLManager.mVRAM = 0; + if (gGLManager.mVRAM != 0) + { + LL_INFOS() << "SDL detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; + } + } + // If VRAM is not detected, that is handled later + + // *TODO: Now would be an appropriate time to check for some + // explicitly unsupported cards. + //const char* RENDERER = (const char*) glGetString(GL_RENDERER); + + SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &redBits); + SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &greenBits); + SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &blueBits); + SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &alphaBits); + SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depthBits); + SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencilBits); + + LL_INFOS() << "GL buffer:" << LL_ENDL; + LL_INFOS() << " Red Bits " << S32(redBits) << LL_ENDL; + LL_INFOS() << " Green Bits " << S32(greenBits) << LL_ENDL; + LL_INFOS() << " Blue Bits " << S32(blueBits) << LL_ENDL; + LL_INFOS() << " Alpha Bits " << S32(alphaBits) << LL_ENDL; + LL_INFOS() << " Depth Bits " << S32(depthBits) << LL_ENDL; + LL_INFOS() << " Stencil Bits " << S32(stencilBits) << LL_ENDL; + + GLint colorBits = redBits + greenBits + blueBits + alphaBits; + // fixme: actually, it's REALLY important for picking that we get at + // least 8 bits each of red,green,blue. Alpha we can be a bit more + // relaxed about if we have to. + if (colorBits < 32) + { + close(); + setupFailure( + "Second Life requires True Color (32-bit) to run in a window.\n" + "Please go to Control Panels -> Display -> Settings and\n" + "set the screen to 32-bit color.\n" + "Alternately, if you choose to run fullscreen, Second Life\n" + "will automatically adjust the screen each time it runs.", + "Error", + OSMB_OK); + return FALSE; + } + +#if LL_X11 + /* Grab the window manager specific information */ + SDL_SysWMinfo info; + SDL_VERSION(&info.version); + if ( SDL_GetWindowWMInfo(mWindow, &info) ) + { + /* Save the information for later use */ + if ( info.subsystem == SDL_SYSWM_X11 ) + { + mSDL_Display = info.info.x11.display; + mSDL_XWindowID = info.info.x11.window; + } + else + { + LL_WARNS() << "We're not running under X11? Wild." + << LL_ENDL; + } + } + else + { + LL_WARNS() << "We're not running under any known WM. Wild." + << LL_ENDL; + } +#endif // LL_X11 + + + SDL_StartTextInput(); + //make sure multisampling is disabled by default + glDisable(GL_MULTISAMPLE_ARB); + + // Don't need to get the current gamma, since there's a call that restores it to the system defaults. + return TRUE; +} + + +// changing fullscreen resolution, or switching between windowed and fullscreen mode. +BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) +{ + const BOOL needsRebuild = TRUE; // Just nuke the context and start over. + BOOL result = true; + + LL_INFOS() << "switchContext, fullscreen=" << fullscreen << LL_ENDL; + stop_glerror(); + if(needsRebuild) + { + destroyContext(); + result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); + if (result) + { + gGLManager.initGL(); + + //start with arrow cursor + initCursors(mUseLegacyCursors); // Legacy cursor setting from main program + setCursor( UI_CURSOR_ARROW ); + } + } + + stop_glerror(); + + return result; +} + +void LLWindowSDL::destroyContext() +{ + LL_INFOS() << "destroyContext begins" << LL_ENDL; + + SDL_StopTextInput(); +#if LL_X11 + mSDL_Display = NULL; + mSDL_XWindowID = None; + Lock_Display = NULL; + Unlock_Display = NULL; +#endif // LL_X11 + + // Clean up remaining GL state before blowing away window + LL_INFOS() << "shutdownGL begins" << LL_ENDL; + gGLManager.shutdownGL(); + LL_INFOS() << "SDL_QuitSS/VID begins" << LL_ENDL; + SDL_QuitSubSystem(SDL_INIT_VIDEO); // *FIX: this might be risky... + + mWindow = NULL; +} + +LLWindowSDL::~LLWindowSDL() +{ + quitCursors(); + destroyContext(); + + if(mSupportedResolutions != NULL) + { + delete []mSupportedResolutions; + } + + gWindowImplementation = NULL; +} + + +void LLWindowSDL::show() +{ + // *FIX: What to do with SDL? +} + +void LLWindowSDL::hide() +{ + // *FIX: What to do with SDL? +} + +//virtual +void LLWindowSDL::minimize() +{ + // *FIX: What to do with SDL? +} + +//virtual +void LLWindowSDL::restore() +{ + // *FIX: What to do with SDL? +} + + +// close() destroys all OS-specific code associated with a window. +// Usually called from LLWindowManager::destroyWindow() +void LLWindowSDL::close() +{ + // Is window is already closed? + // if (!mWindow) + // { + // return; + // } + + // Make sure cursor is visible and we haven't mangled the clipping state. + setMouseClipping(FALSE); + showCursor(); + + destroyContext(); +} + +BOOL LLWindowSDL::isValid() +{ + return (mWindow != NULL); +} + +BOOL LLWindowSDL::getVisible() +{ + BOOL result = FALSE; + + // *FIX: This isn't really right... + // Then what is? + if (mWindow) + { + result = TRUE; + } + + return(result); +} + +BOOL LLWindowSDL::getMinimized() +{ + BOOL result = FALSE; + + if (mWindow && (1 == mIsMinimized)) + { + result = TRUE; + } + return(result); +} + +BOOL LLWindowSDL::getMaximized() +{ + BOOL result = FALSE; + + if (mWindow) + { + // TODO + } + + return(result); +} + +BOOL LLWindowSDL::maximize() +{ + // TODO + return FALSE; +} + +BOOL LLWindowSDL::getFullscreen() +{ + return mFullscreen; +} + +BOOL LLWindowSDL::getPosition(LLCoordScreen *position) +{ + // *FIX: can anything be done with this? + position->mX = 0; + position->mY = 0; + return TRUE; +} + +BOOL LLWindowSDL::getSize(LLCoordScreen *size) +{ + if (mSurface) + { + size->mX = mSurface->w; + size->mY = mSurface->h; + return (TRUE); + } + + return (FALSE); +} + +BOOL LLWindowSDL::getSize(LLCoordWindow *size) +{ + if (mSurface) + { + size->mX = mSurface->w; + size->mY = mSurface->h; + return (TRUE); + } + + return (FALSE); +} + +BOOL LLWindowSDL::setPosition(const LLCoordScreen position) +{ + if(mWindow) + { + // *FIX: (?) + //MacMoveWindow(mWindow, position.mX, position.mY, false); + } + + return TRUE; +} + +template< typename T > bool setSizeImpl( const T& newSize, SDL_Window *pWin ) +{ + if( !pWin ) + return false; + + auto nFlags = SDL_GetWindowFlags( pWin ); + + if( nFlags & SDL_WINDOW_MAXIMIZED ) + SDL_RestoreWindow( pWin ); + + + SDL_SetWindowSize( pWin, newSize.mX, newSize.mY ); + SDL_Event event; + event.type = SDL_WINDOWEVENT; + event.window.event = SDL_WINDOWEVENT_RESIZED; + event.window.windowID = SDL_GetWindowID( pWin ); + event.window.data1 = newSize.mX; + event.window.data2 = newSize.mY; + SDL_PushEvent( &event ); + + return true; +} + +BOOL LLWindowSDL::setSizeImpl(const LLCoordScreen size) +{ + return ::setSizeImpl( size, mWindow ); +} + +BOOL LLWindowSDL::setSizeImpl(const LLCoordWindow size) +{ + return ::setSizeImpl( size, mWindow ); +} + + +void LLWindowSDL::swapBuffers() +{ + if (mWindow) + { + SDL_GL_SwapWindow( mWindow ); + } +} + +U32 LLWindowSDL::getFSAASamples() +{ + return mFSAASamples; +} + +void LLWindowSDL::setFSAASamples(const U32 samples) +{ + mFSAASamples = samples; +} + +F32 LLWindowSDL::getGamma() +{ + return 1/mGamma; +} + +BOOL LLWindowSDL::restoreGamma() +{ + //CGDisplayRestoreColorSyncSettings(); + // SDL_SetGamma(1.0f, 1.0f, 1.0f); + return true; +} + +BOOL LLWindowSDL::setGamma(const F32 gamma) +{ + mGamma = gamma; + if (mGamma == 0) mGamma = 0.1f; + mGamma = 1/mGamma; + // SDL_SetGamma(mGamma, mGamma, mGamma); + return true; +} + +BOOL LLWindowSDL::isCursorHidden() +{ + return mCursorHidden; +} + + + +// Constrains the mouse to the window. +void LLWindowSDL::setMouseClipping( BOOL b ) +{ + //SDL_WM_GrabInput(b ? SDL_GRAB_ON : SDL_GRAB_OFF); +} + +// virtual +void LLWindowSDL::setMinSize(U32 min_width, U32 min_height, bool enforce_immediately) +{ + LLWindow::setMinSize(min_width, min_height, enforce_immediately); + +#if LL_X11 + // Set the minimum size limits for X11 window + // so the window manager doesn't allow resizing below those limits. + XSizeHints* hints = XAllocSizeHints(); + hints->flags |= PMinSize; + hints->min_width = mMinWindowWidth; + hints->min_height = mMinWindowHeight; + + XSetWMNormalHints(mSDL_Display, mSDL_XWindowID, hints); + + XFree(hints); +#endif +} + +BOOL LLWindowSDL::setCursorPosition(const LLCoordWindow position) +{ + BOOL result = TRUE; + LLCoordScreen screen_pos; + + if (!convertCoords(position, &screen_pos)) + { + return FALSE; + } + + //LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; + + // do the actual forced cursor move. + SDL_WarpMouseInWindow(mWindow, screen_pos.mX, screen_pos.mY); + + //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; + + return result; +} + +BOOL LLWindowSDL::getCursorPosition(LLCoordWindow *position) +{ + //Point cursor_point; + LLCoordScreen screen_pos; + + //GetMouse(&cursor_point); + int x, y; + SDL_GetMouseState(&x, &y); + + screen_pos.mX = x; + screen_pos.mY = y; + + return convertCoords(screen_pos, position); +} + + +F32 LLWindowSDL::getNativeAspectRatio() +{ + // MBW -- there are a couple of bad assumptions here. One is that the display list won't include + // ridiculous resolutions nobody would ever use. The other is that the list is in order. + + // New assumptions: + // - pixels are square (the only reasonable choice, really) + // - The user runs their display at a native resolution, so the resolution of the display + // when the app is launched has an aspect ratio that matches the monitor. + + //RN: actually, the assumption that there are no ridiculous resolutions (above the display's native capabilities) has + // been born out in my experience. + // Pixels are often not square (just ask the people who run their LCDs at 1024x768 or 800x600 when running fullscreen, like me) + // The ordering of display list is a blind assumption though, so we should check for max values + // Things might be different on the Mac though, so I'll defer to MBW + + // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution + // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. + + if (mOverrideAspectRatio > 0.f) + { + return mOverrideAspectRatio; + } + + return mOriginalAspectRatio; +} + +F32 LLWindowSDL::getPixelAspectRatio() +{ + F32 pixel_aspect = 1.f; + if (getFullscreen()) + { + LLCoordScreen screen_size; + if (getSize(&screen_size)) + { + pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; + } + } + + return pixel_aspect; +} + + +// This is to support 'temporarily windowed' mode so that +// dialogs are still usable in fullscreen. +void LLWindowSDL::beforeDialog() +{ + bool running_x11 = false; +#if LL_X11 + running_x11 = (mSDL_XWindowID != None); +#endif //LL_X11 + + LL_INFOS() << "LLWindowSDL::beforeDialog()" << LL_ENDL; + + if (SDLReallyCaptureInput(FALSE)) // must ungrab input so popup works! + { + if (mFullscreen) + { + // need to temporarily go non-fullscreen; bless SDL + // for providing a SDL_WM_ToggleFullScreen() - though + // it only works in X11 + if (running_x11 && mWindow) + { + SDL_SetWindowFullscreen( mWindow, 0 ); + } + } + } + +#if LL_X11 + if (mSDL_Display) + { + // Everything that we/SDL asked for should happen before we + // potentially hand control over to GTK. + maybe_lock_display(); + XSync(mSDL_Display, False); + maybe_unlock_display(); + } +#endif // LL_X11 + + maybe_lock_display(); +} + +void LLWindowSDL::afterDialog() +{ + bool running_x11 = false; +#if LL_X11 + running_x11 = (mSDL_XWindowID != None); +#endif //LL_X11 + + LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; + + maybe_unlock_display(); + + if (mFullscreen) + { + // need to restore fullscreen mode after dialog - only works + // in X11 + if (running_x11 && mWindow) + { + SDL_SetWindowFullscreen( mWindow, 0 ); + } + } +} + + +#if LL_X11 +// set/reset the XWMHints flag for 'urgency' that usually makes the icon flash +void LLWindowSDL::x11_set_urgent(BOOL urgent) +{ + if (mSDL_Display && !mFullscreen) + { + XWMHints *wm_hints; + + LL_INFOS() << "X11 hint for urgency, " << urgent << LL_ENDL; + + maybe_lock_display(); + wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); + if (!wm_hints) + wm_hints = XAllocWMHints(); + + if (urgent) + wm_hints->flags |= XUrgencyHint; + else + wm_hints->flags &= ~XUrgencyHint; + + XSetWMHints(mSDL_Display, mSDL_XWindowID, wm_hints); + XFree(wm_hints); + XSync(mSDL_Display, False); + maybe_unlock_display(); + } +} +#endif // LL_X11 + +void LLWindowSDL::flashIcon(F32 seconds) +{ + if (getMinimized()) // Moved this here from llviewermessage.cpp + { +#if !LL_X11 + LL_INFOS() << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; +#else + LL_INFOS() << "X11 LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; + + F32 remaining_time = mFlashTimer.getRemainingTimeF32(); + if (remaining_time < seconds) + remaining_time = seconds; + mFlashTimer.reset(); + mFlashTimer.setTimerExpirySec(remaining_time); + + x11_set_urgent(TRUE); + mFlashing = TRUE; +#endif // LL_X11 + } +} + +BOOL LLWindowSDL::isClipboardTextAvailable() +{ + return mSDL_Display && XGetSelectionOwner(mSDL_Display, XA_CLIPBOARD) != None; +} + +BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst) +{ + return getSelectionText(XA_CLIPBOARD, dst); +} + +BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s) +{ + return setSelectionText(XA_CLIPBOARD, s); +} + +BOOL LLWindowSDL::isPrimaryTextAvailable() +{ + LLWString text; + return getSelectionText(XA_PRIMARY, text) && !text.empty(); +} + +BOOL LLWindowSDL::pasteTextFromPrimary(LLWString &dst) +{ + return getSelectionText(XA_PRIMARY, dst); +} + +BOOL LLWindowSDL::copyTextToPrimary(const LLWString &s) +{ + return setSelectionText(XA_PRIMARY, s); +} + +LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions) +{ + if (!mSupportedResolutions) + { + mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; + mNumSupportedResolutions = 0; + + // Use display no from mWindow/mSurface here? + int max = SDL_GetNumDisplayModes(0); + max = llclamp( max, 0, MAX_NUM_RESOLUTIONS ); + + for( int i =0; i < max; ++i ) + { + SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 }; + if (SDL_GetDisplayMode( 0 , i, &mode) != 0) + { + continue; + } + + int w = mode.w; + int h = mode.h; + if ((w >= 800) && (h >= 600)) + { + // make sure we don't add the same resolution multiple times! + if ( (mNumSupportedResolutions == 0) || + ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) && + (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) ) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = w; + mSupportedResolutions[mNumSupportedResolutions].mHeight = h; + mNumSupportedResolutions++; + } + } + } + } + + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; +} + +BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to) +{ + if (!to) + return FALSE; + + to->mX = from.mX; + to->mY = mSurface->h - from.mY - 1; + + return TRUE; +} + +BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) +{ + if (!to) + return FALSE; + + to->mX = from.mX; + to->mY = mSurface->h - from.mY - 1; + + return TRUE; +} + +BOOL LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) +{ + if (!to) + return FALSE; + + // In the fullscreen case, window and screen coordinates are the same. + to->mX = from.mX; + to->mY = from.mY; + return (TRUE); +} + +BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) +{ + if (!to) + return FALSE; + + // In the fullscreen case, window and screen coordinates are the same. + to->mX = from.mX; + to->mY = from.mY; + return (TRUE); +} + +BOOL LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) +{ + LLCoordWindow window_coord; + + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +} + +BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to) +{ + LLCoordWindow window_coord; + + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +} + + + + +void LLWindowSDL::setupFailure(const std::string& text, const std::string& caption, U32 type) +{ + destroyContext(); + + OSMessageBox(text, caption, type); +} + +BOOL LLWindowSDL::SDLReallyCaptureInput(BOOL capture) +{ + // note: this used to be safe to call nestedly, but in the + // end that's not really a wise usage pattern, so don't. + + if (capture) + mReallyCapturedCount = 1; + else + mReallyCapturedCount = 0; + + bool wantGrab; + if (mReallyCapturedCount <= 0) // uncapture + { + wantGrab = false; + } else // capture + { + wantGrab = true; + } + + if (mReallyCapturedCount < 0) // yuck, imbalance. + { + mReallyCapturedCount = 0; + LL_WARNS() << "ReallyCapture count was < 0" << LL_ENDL; + } + + bool newGrab = wantGrab; + +#if LL_X11 + if (!mFullscreen) /* only bother if we're windowed anyway */ + { + if (mSDL_Display) + { + /* we dirtily mix raw X11 with SDL so that our pointer + isn't (as often) constrained to the limits of the + window while grabbed, which feels nicer and + hopefully eliminates some reported 'sticky pointer' + problems. We use raw X11 instead of + SDL_WM_GrabInput() because the latter constrains + the pointer to the window and also steals all + *keyboard* input from the window manager, which was + frustrating users. */ + int result; + if (wantGrab == true) + { + maybe_lock_display(); + result = XGrabPointer(mSDL_Display, mSDL_XWindowID, + True, 0, GrabModeAsync, + GrabModeAsync, + None, None, CurrentTime); + maybe_unlock_display(); + if (GrabSuccess == result) + newGrab = true; + else + newGrab = false; + } + else + { + newGrab = false; + + maybe_lock_display(); + XUngrabPointer(mSDL_Display, CurrentTime); + // Make sure the ungrab happens RIGHT NOW. + XSync(mSDL_Display, False); + maybe_unlock_display(); + } + } + } +#endif // LL_X11 + // return boolean success for whether we ended up in the desired state + return capture == newGrab; +} + +U32 LLWindowSDL::SDLCheckGrabbyKeys(U32 keysym, BOOL gain) +{ + /* part of the fix for SL-13243: Some popular window managers like + to totally eat alt-drag for the purposes of moving windows. We + spoil their day by acquiring the exclusive X11 mouse lock for as + long as ALT is held down, so the window manager can't easily + see what's happening. Tested successfully with Metacity. + And... do the same with CTRL, for other darn WMs. We don't + care about other metakeys as SL doesn't use them with dragging + (for now). */ + + /* We maintain a bitmap of critical keys which are up and down + instead of simply key-counting, because SDL sometimes reports + misbalanced keyup/keydown event pairs to us for whatever reason. */ + + U32 mask = 0; + switch (keysym) + { + case SDLK_LALT: + mask = 1U << 0; break; + case SDLK_RALT: + mask = 1U << 1; break; + case SDLK_LCTRL: + mask = 1U << 2; break; + case SDLK_RCTRL: + mask = 1U << 3; break; + default: + break; + } + + if (gain) + mGrabbyKeyFlags |= mask; + else + mGrabbyKeyFlags &= ~mask; + + //LL_INFOS() << "mGrabbyKeyFlags=" << mGrabbyKeyFlags << LL_ENDL; + + /* 0 means we don't need to mousegrab, otherwise grab. */ + return mGrabbyKeyFlags; +} + + +void check_vm_bloat() +{ +#if LL_LINUX + // watch our own VM and RSS sizes, warn if we bloated rapidly + static const std::string STATS_FILE = "/proc/self/stat"; + FILE *fp = fopen(STATS_FILE.c_str(), "r"); + if (fp) + { + static long long last_vm_size = 0; + static long long last_rss_size = 0; + const long long significant_vm_difference = 250 * 1024*1024; + const long long significant_rss_difference = 50 * 1024*1024; + long long this_vm_size = 0; + long long this_rss_size = 0; + + ssize_t res; + size_t dummy; + char *ptr = NULL; + for (int i=0; i<22; ++i) // parse past the values we don't want + { + res = getdelim(&ptr, &dummy, ' ', fp); + if (-1 == res) + { + LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; + goto finally; + } + free(ptr); + ptr = NULL; + } + // 23rd space-delimited entry is vsize + res = getdelim(&ptr, &dummy, ' ', fp); + llassert(ptr); + if (-1 == res) + { + LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; + goto finally; + } + this_vm_size = atoll(ptr); + free(ptr); + ptr = NULL; + // 24th space-delimited entry is RSS + res = getdelim(&ptr, &dummy, ' ', fp); + llassert(ptr); + if (-1 == res) + { + LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; + goto finally; + } + this_rss_size = getpagesize() * atoll(ptr); + free(ptr); + ptr = NULL; + + LL_INFOS() << "VM SIZE IS NOW " << (this_vm_size/(1024*1024)) << " MB, RSS SIZE IS NOW " << (this_rss_size/(1024*1024)) << " MB" << LL_ENDL; + + if (llabs(last_vm_size - this_vm_size) > + significant_vm_difference) + { + if (this_vm_size > last_vm_size) + { + LL_WARNS() << "VM size grew by " << (this_vm_size - last_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + else + { + LL_INFOS() << "VM size shrank by " << (last_vm_size - this_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + } + + if (llabs(last_rss_size - this_rss_size) > + significant_rss_difference) + { + if (this_rss_size > last_rss_size) + { + LL_WARNS() << "RSS size grew by " << (this_rss_size - last_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + else + { + LL_INFOS() << "RSS size shrank by " << (last_rss_size - this_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + } + + last_rss_size = this_rss_size; + last_vm_size = this_vm_size; + +finally: + if (NULL != ptr) + { + free(ptr); + ptr = NULL; + } + fclose(fp); + } +#endif // LL_LINUX +} + + +// virtual +void LLWindowSDL::processMiscNativeEvents() +{ +#if LL_GLIB + // Pump until we've nothing left to do or passed 1/15th of a + // second pumping for this frame. + static LLTimer pump_timer; + pump_timer.reset(); + pump_timer.setTimerExpirySec(1.0f / 15.0f); + do + { + g_main_context_iteration(g_main_context_default(), FALSE); + } while( g_main_context_pending(g_main_context_default()) && !pump_timer.hasExpired()); +#endif + + // hack - doesn't belong here - but this is just for debugging + if (getenv("LL_DEBUG_BLOAT")) + { + check_vm_bloat(); + } +} + +void LLWindowSDL::gatherInput() +{ + const Uint32 CLICK_THRESHOLD = 300; // milliseconds + static int leftClick = 0; + static int rightClick = 0; + static Uint32 lastLeftDown = 0; + static Uint32 lastRightDown = 0; + SDL_Event event; + + // Handle all outstanding SDL events + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_MOUSEWHEEL: + if( event.wheel.y != 0 ) + mCallbacks->handleScrollWheel(this, -event.wheel.y); + break; + + case SDL_MOUSEMOTION: + { + LLCoordWindow winCoord(event.button.x, event.button.y); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + MASK mask = gKeyboard->currentMask(TRUE); + mCallbacks->handleMouseMove(this, openGlCoord, mask); + break; + } + + case SDL_TEXTINPUT: + { + auto string = utf8str_to_utf16str( event.text.text ); + mKeyModifiers = gKeyboard->currentMask( FALSE ); + mInputType = "textinput"; + for( auto key: string ) + { + mKeyVirtualKey = key; + + if( (MASK_CONTROL|MASK_ALT)&mKeyModifiers ) + gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers ); + else + handleUnicodeUTF16( key, mKeyModifiers ); + } + break; + } + + case SDL_KEYDOWN: + mKeyVirtualKey = event.key.keysym.sym; + mKeyModifiers = event.key.keysym.mod; + mInputType = "keydown"; + + gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers ); + + // Slightly hacky :| To make the viewer honor enter (eg to accept form input) we've to not only send handleKeyDown but also send a + // invoke handleUnicodeUTF16 in case the user hits return. + // Note that we cannot blindly use handleUnicodeUTF16 for each SDL_KEYDOWN. Doing so will create bogus keyboard input (like % for cursor left). + if( mKeyVirtualKey == SDLK_RETURN ) + handleUnicodeUTF16( mKeyVirtualKey, mKeyModifiers ); + + // part of the fix for SL-13243 + if (SDLCheckGrabbyKeys(event.key.keysym.sym, TRUE) != 0) + SDLReallyCaptureInput(TRUE); + + break; + + case SDL_KEYUP: + mKeyVirtualKey = event.key.keysym.sym; + mKeyModifiers = event.key.keysym.mod; + mInputType = "keyup"; + + if (SDLCheckGrabbyKeys(mKeyVirtualKey, FALSE) == 0) + SDLReallyCaptureInput(FALSE); // part of the fix for SL-13243 + + gKeyboard->handleKeyUp(mKeyVirtualKey,mKeyModifiers); + break; + + case SDL_MOUSEBUTTONDOWN: + { + bool isDoubleClick = false; + LLCoordWindow winCoord(event.button.x, event.button.y); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + MASK mask = gKeyboard->currentMask(TRUE); + + if (event.button.button == SDL_BUTTON_LEFT) // SDL doesn't manage double clicking... + { + Uint32 now = SDL_GetTicks(); + if ((now - lastLeftDown) > CLICK_THRESHOLD) + leftClick = 1; + else + { + if (++leftClick >= 2) + { + leftClick = 0; + isDoubleClick = true; + } + } + lastLeftDown = now; + } + else if (event.button.button == SDL_BUTTON_RIGHT) + { + Uint32 now = SDL_GetTicks(); + if ((now - lastRightDown) > CLICK_THRESHOLD) + rightClick = 1; + else + { + if (++rightClick >= 2) + { + rightClick = 0; + isDoubleClick = true; + } + } + lastRightDown = now; + } + + if (event.button.button == SDL_BUTTON_LEFT) // left + { + if (isDoubleClick) + mCallbacks->handleDoubleClick(this, openGlCoord, mask); + else + mCallbacks->handleMouseDown(this, openGlCoord, mask); + } + + else if (event.button.button == SDL_BUTTON_RIGHT) // right + { + mCallbacks->handleRightMouseDown(this, openGlCoord, mask); + } + + else if (event.button.button == SDL_BUTTON_MIDDLE) // middle + { + mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); + } + else if (event.button.button == 4) // mousewheel up...thanks to X11 for making SDL consider these "buttons". + mCallbacks->handleScrollWheel(this, -1); + else if (event.button.button == 5) // mousewheel down...thanks to X11 for making SDL consider these "buttons". + mCallbacks->handleScrollWheel(this, 1); + + break; + } + + case SDL_MOUSEBUTTONUP: + { + LLCoordWindow winCoord(event.button.x, event.button.y); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + MASK mask = gKeyboard->currentMask(TRUE); + + if (event.button.button == SDL_BUTTON_LEFT) // left + mCallbacks->handleMouseUp(this, openGlCoord, mask); + else if (event.button.button == SDL_BUTTON_RIGHT) // right + mCallbacks->handleRightMouseUp(this, openGlCoord, mask); + else if (event.button.button == SDL_BUTTON_MIDDLE) // middle + mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask); + // don't handle mousewheel here... + + break; + } + + case SDL_WINDOWEVENT: // *FIX: handle this? + { + if( event.window.event == SDL_WINDOWEVENT_RESIZED + /* || event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED*/ ) // SDL_WINDOWEVENT_SIZE_CHANGED is followed by SDL_WINDOWEVENT_RESIZED, so handling one shall be enough + { + LL_INFOS() << "Handling a resize event: " << event.window.data1 << "x" << event.window.data2 << LL_ENDL; + + S32 width = llmax(event.window.data1, (S32)mMinWindowWidth); + S32 height = llmax(event.window.data2, (S32)mMinWindowHeight); + mSurface = SDL_GetWindowSurface( mWindow ); + + // *FIX: I'm not sure this is necessary! + // I think is is not + // SDL_SetWindowSize(mWindow, width, height); + // + + mCallbacks->handleResize(this, width, height); + } + else if( event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED ) // What about SDL_WINDOWEVENT_ENTER (mouse focus) + { + // We have to do our own state massaging because SDL + // can send us two unfocus events in a row for example, + // which confuses the focus code [SL-24071]. + mHaveInputFocus = true; + + mCallbacks->handleFocus(this); + } + else if( event.window.event == SDL_WINDOWEVENT_FOCUS_LOST ) // What about SDL_WINDOWEVENT_LEAVE (mouse focus) + { + // We have to do our own state massaging because SDL + // can send us two unfocus events in a row for example, + // which confuses the focus code [SL-24071]. + mHaveInputFocus = false; + + mCallbacks->handleFocusLost(this); + } + else if( event.window.event == SDL_WINDOWEVENT_MINIMIZED || + event.window.event == SDL_WINDOWEVENT_MAXIMIZED || + event.window.event == SDL_WINDOWEVENT_RESTORED || + event.window.event == SDL_WINDOWEVENT_EXPOSED || + event.window.event == SDL_WINDOWEVENT_SHOWN ) + { + mIsMinimized = (event.window.event == SDL_WINDOWEVENT_MINIMIZED); + + mCallbacks->handleActivate(this, !mIsMinimized); + LL_INFOS() << "SDL deiconification state switched to " << mIsMinimized << LL_ENDL; + } + + break; + } + case SDL_QUIT: + if(mCallbacks->handleCloseRequest(this)) + { + // Get the app to initiate cleanup. + mCallbacks->handleQuit(this); + // The app is responsible for calling destroyWindow when done with GL + } + break; + default: + //LL_INFOS() << "Unhandled SDL event type " << event.type << LL_ENDL; + break; + } + } + + updateCursor(); + +#if LL_X11 + // This is a good time to stop flashing the icon if our mFlashTimer has + // expired. + if (mFlashing && mFlashTimer.hasExpired()) + { + x11_set_urgent(FALSE); + mFlashing = FALSE; + } +#endif // LL_X11 +} + +static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty) +{ + SDL_Cursor *sdlcursor = NULL; + SDL_Surface *bmpsurface; + + // Load cursor pixel data from BMP file + bmpsurface = Load_BMP_Resource(filename); + if (bmpsurface && bmpsurface->w%8==0) + { + SDL_Surface *cursurface; + LL_DEBUGS() << "Loaded cursor file " << filename << " " + << bmpsurface->w << "x" << bmpsurface->h << LL_ENDL; + cursurface = SDL_CreateRGBSurface (SDL_SWSURFACE, + bmpsurface->w, + bmpsurface->h, + 32, + SDL_SwapLE32(0xFFU), + SDL_SwapLE32(0xFF00U), + SDL_SwapLE32(0xFF0000U), + SDL_SwapLE32(0xFF000000U)); + SDL_FillRect(cursurface, NULL, SDL_SwapLE32(0x00000000U)); + + // Blit the cursor pixel data onto a 32-bit RGBA surface so we + // only have to cope with processing one type of pixel format. + if (0 == SDL_BlitSurface(bmpsurface, NULL, + cursurface, NULL)) + { + // n.b. we already checked that width is a multiple of 8. + const int bitmap_bytes = (cursurface->w * cursurface->h) / 8; + unsigned char *cursor_data = new unsigned char[bitmap_bytes]; + unsigned char *cursor_mask = new unsigned char[bitmap_bytes]; + memset(cursor_data, 0, bitmap_bytes); + memset(cursor_mask, 0, bitmap_bytes); + int i,j; + // Walk the RGBA cursor pixel data, extracting both data and + // mask to build SDL-friendly cursor bitmaps from. The mask + // is inferred by color-keying against 200,200,200 + for (i=0; ih; ++i) { + for (j=0; jw; ++j) { + U8 *pixelp = + ((U8*)cursurface->pixels) + + cursurface->pitch * i + + j*cursurface->format->BytesPerPixel; + U8 srcred = pixelp[0]; + U8 srcgreen = pixelp[1]; + U8 srcblue = pixelp[2]; + BOOL mask_bit = (srcred != 200) + || (srcgreen != 200) + || (srcblue != 200); + BOOL data_bit = mask_bit && (srcgreen <= 80);//not 0x80 + unsigned char bit_offset = (cursurface->w/8) * i + + j/8; + cursor_data[bit_offset] |= (data_bit) << (7 - (j&7)); + cursor_mask[bit_offset] |= (mask_bit) << (7 - (j&7)); + } + } + sdlcursor = SDL_CreateCursor((Uint8*)cursor_data, + (Uint8*)cursor_mask, + cursurface->w, cursurface->h, + hotx, hoty); + delete[] cursor_data; + delete[] cursor_mask; + } else { + LL_WARNS() << "CURSOR BLIT FAILURE, cursurface: " << cursurface << LL_ENDL; + } + SDL_FreeSurface(cursurface); + SDL_FreeSurface(bmpsurface); + } else { + LL_WARNS() << "CURSOR LOAD FAILURE " << filename << LL_ENDL; + } + + return sdlcursor; +} + +void LLWindowSDL::updateCursor() +{ + if (ATIbug) { + // cursor-updating is very flaky when this bug is + // present; do nothing. + return; + } + + if (mCurrentCursor != mNextCursor) + { + if (mNextCursor < UI_CURSOR_COUNT) + { + SDL_Cursor *sdlcursor = mSDLCursors[mNextCursor]; + // Try to default to the arrow for any cursors that + // did not load correctly. + if (!sdlcursor && mSDLCursors[UI_CURSOR_ARROW]) + sdlcursor = mSDLCursors[UI_CURSOR_ARROW]; + if (sdlcursor) + SDL_SetCursor(sdlcursor); + } else { + LL_WARNS() << "Tried to set invalid cursor number " << mNextCursor << LL_ENDL; + } + mCurrentCursor = mNextCursor; + } +} + +//void LLWindowSDL::initCursors() +void LLWindowSDL::initCursors(BOOL useLegacyCursors) // Legacy cursor setting from main program +{ + int i; + // Blank the cursor pointer array for those we may miss. + for (i=0; i Legacy cursor setting from main program + mSDLCursors[UI_CURSOR_TOOLSIT] = makeSDLCursorFromBMP("toolsit.BMP",20,15); + mSDLCursors[UI_CURSOR_TOOLBUY] = makeSDLCursorFromBMP("toolbuy.BMP",20,15); + mSDLCursors[UI_CURSOR_TOOLOPEN] = makeSDLCursorFromBMP("toolopen.BMP",20,15);*/ + if (useLegacyCursors) { + mSDLCursors[UI_CURSOR_TOOLSIT] = makeSDLCursorFromBMP("toolsit-legacy.BMP",0,0); + mSDLCursors[UI_CURSOR_TOOLBUY] = makeSDLCursorFromBMP("toolbuy-legacy.BMP",0,0); + mSDLCursors[UI_CURSOR_TOOLOPEN] = makeSDLCursorFromBMP("toolopen-legacy.BMP",0,0); + mSDLCursors[UI_CURSOR_TOOLPAY] = makeSDLCursorFromBMP("toolpay-legacy.BMP",0,0); + } + else + { + mSDLCursors[UI_CURSOR_TOOLSIT] = makeSDLCursorFromBMP("toolsit.BMP",20,15); + mSDLCursors[UI_CURSOR_TOOLBUY] = makeSDLCursorFromBMP("toolbuy.BMP",20,15); + mSDLCursors[UI_CURSOR_TOOLOPEN] = makeSDLCursorFromBMP("toolopen.BMP",20,15); + mSDLCursors[UI_CURSOR_TOOLPAY] = makeSDLCursorFromBMP("toolbuy.BMP",20,15); + } + // + mSDLCursors[UI_CURSOR_TOOLPATHFINDING] = makeSDLCursorFromBMP("lltoolpathfinding.BMP", 16, 16); + mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_START] = makeSDLCursorFromBMP("lltoolpathfindingpathstart.BMP", 16, 16); + mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD] = makeSDLCursorFromBMP("lltoolpathfindingpathstartadd.BMP", 16, 16); + mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_END] = makeSDLCursorFromBMP("lltoolpathfindingpathend.BMP", 16, 16); + mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD] = makeSDLCursorFromBMP("lltoolpathfindingpathendadd.BMP", 16, 16); + mSDLCursors[UI_CURSOR_TOOLNO] = makeSDLCursorFromBMP("llno.BMP",8,8); + + if (getenv("LL_ATI_MOUSE_CURSOR_BUG") != NULL) { + LL_INFOS() << "Disabling cursor updating due to LL_ATI_MOUSE_CURSOR_BUG" << LL_ENDL; + ATIbug = true; + } +} + +void LLWindowSDL::quitCursors() +{ + int i; + if (mWindow) + { + for (i=0; i Reopen stdin, stdout, and stderr to /dev/null. + // It's good practice to always have those file + // descriptors open to something, lest the exec'd + // program actually try to use them. + FILE *result; + result = freopen("/dev/null","r",stdin); + if (result == NULL) + { + LL_WARNS() << "Error reopening stdin for web browser: " + << strerror(errno) << LL_ENDL; + } + result = freopen("/dev/null","w",stdout); + if (result == NULL) + { + LL_WARNS() << "Error reopening stdout for web browser: " + << strerror(errno) << LL_ENDL; + } + result = freopen("/dev/null","w",stderr); + if (result == NULL) + { + LL_WARNS() << "Error reopening stderr for web browser: " + << strerror(errno) << LL_ENDL; + } + // end ourself by running the command + execv(cmd.c_str(), argv); /* Flawfinder: ignore */ + // if execv returns at all, there was a problem. + LL_WARNS() << "execv failure when trying to start " << cmd << LL_ENDL; + _exit(1); // _exit because we don't want atexit() clean-up! + } else { + if (pid > 0) + { + // parent - wait for child to die + int childExitStatus; + waitpid(pid, &childExitStatus, 0); + } else { + LL_WARNS() << "fork failure." << LL_ENDL; + } + } +} +#endif + +// Open a URL with the user's default web browser. +// Must begin with protocol identifier. +void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) +{ + bool found = false; + S32 i; + for (i = 0; i < gURLProtocolWhitelistCount; i++) + { + if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) + { + found = true; + break; + } + } + + if (!found) + { + LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; + return; + } + + LL_INFOS() << "spawn_web_browser: " << escaped_url << LL_ENDL; + +#if LL_LINUX +# if LL_X11 + if (mSDL_Display) + { + maybe_lock_display(); + // Just in case - before forking. + XSync(mSDL_Display, False); + maybe_unlock_display(); + } +# endif // LL_X11 + + std::string cmd, arg; + cmd = gDirUtilp->getAppRODataDir(); + cmd += gDirUtilp->getDirDelimiter(); + cmd += "etc"; + cmd += gDirUtilp->getDirDelimiter(); + cmd += "launch_url.sh"; + arg = escaped_url; + exec_cmd(cmd, arg); +#endif // LL_LINUX + + LL_INFOS() << "spawn_web_browser returning." << LL_ENDL; +} + +void LLWindowSDL::openFile(const std::string& file_name) +{ + spawnWebBrowser("file://"+file_name,TRUE); +} + +void *LLWindowSDL::getPlatformWindow() +{ + return NULL; +} + +void LLWindowSDL::bringToFront() +{ + // This is currently used when we are 'launched' to a specific + // map position externally. + LL_INFOS() << "bringToFront" << LL_ENDL; +#if LL_X11 + if (mSDL_Display && !mFullscreen) + { + maybe_lock_display(); + XRaiseWindow(mSDL_Display, mSDL_XWindowID); + XSync(mSDL_Display, False); + maybe_unlock_display(); + } +#endif // LL_X11 +} + +//static +std::vector LLWindowSDL::getDynamicFallbackFontList() +{ + // Use libfontconfig to find us a nice ordered list of fallback fonts + // specific to this system. + std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf"); + const int max_font_count_cutoff = 40; // fonts are expensive in the current system, don't enumerate an arbitrary number of them + // Our 'ideal' font properties which define the sorting results. + // slant=0 means Roman, index=0 means the first face in a font file + // (the one we actually use), weight=80 means medium weight, + // spacing=0 means proportional spacing. + std::string sort_order("slant=0:index=0:weight=80:spacing=0"); + // elide_unicode_coverage removes fonts from the list whose unicode + // range is covered by fonts earlier in the list. This usually + // removes ~90% of the fonts as redundant (which is great because + // the font list can be huge), but might unnecessarily reduce the + // renderable range if for some reason our FreeType actually fails + // to use some of the fonts we want it to. + const bool elide_unicode_coverage = true; + std::vector rtns; + FcFontSet *fs = NULL; + FcPattern *sortpat = NULL; + + LL_INFOS() << "Getting system font list from FontConfig..." << LL_ENDL; + + // If the user has a system-wide language preference, then favor + // fonts from that language group. This doesn't affect the types + // of languages that can be displayed, but ensures that their + // preferred language is rendered from a single consistent font where + // possible. + FL_Locale *locale = NULL; + FL_Success success = FL_FindLocale(&locale, FL_MESSAGES); + if (success != 0) + { + if (success >= 2 && locale->lang) // confident! + { + LL_INFOS("AppInit") << "Language " << locale->lang << LL_ENDL; + LL_INFOS("AppInit") << "Location " << locale->country << LL_ENDL; + LL_INFOS("AppInit") << "Variant " << locale->variant << LL_ENDL; + + LL_INFOS() << "Preferring fonts of language: " + << locale->lang + << LL_ENDL; + sort_order = "lang=" + std::string(locale->lang) + ":" + + sort_order; + } + } + FL_FreeLocale(&locale); + + if (!FcInit()) + { + LL_WARNS() << "FontConfig failed to initialize." << LL_ENDL; + rtns.push_back(final_fallback); + return rtns; + } + + sortpat = FcNameParse((FcChar8*) sort_order.c_str()); + if (sortpat) + { + // Sort the list of system fonts from most-to-least-desirable. + FcResult result; + fs = FcFontSort(NULL, sortpat, elide_unicode_coverage, + NULL, &result); + FcPatternDestroy(sortpat); + } + + int found_font_count = 0; + if (fs) + { + // Get the full pathnames to the fonts, where available, + // which is what we really want. + found_font_count = fs->nfont; + for (int i=0; infont; ++i) + { + FcChar8 *filename; + if (FcResultMatch == FcPatternGetString(fs->fonts[i], + FC_FILE, 0, + &filename) + && filename) + { + rtns.push_back(std::string((const char*)filename)); + if (rtns.size() >= max_font_count_cutoff) + break; // hit limit + } + } + FcFontSetDestroy (fs); + } + + LL_DEBUGS() << "Using font list: " << LL_ENDL; + for (std::vector::iterator it = rtns.begin(); + it != rtns.end(); + ++it) + { + LL_DEBUGS() << " file: " << *it << LL_ENDL; + } + LL_INFOS() << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << LL_ENDL; + + rtns.push_back(final_fallback); + return rtns; +} + +#endif // LL_SDL diff --git a/indra/llwindow/llwindowsdl2.h b/indra/llwindow/llwindowsdl2.h new file mode 100644 index 0000000000..e60827644d --- /dev/null +++ b/indra/llwindow/llwindowsdl2.h @@ -0,0 +1,261 @@ +/** + * @file llwindowsdl.h + * @brief SDL implementation of LLWindow class + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLWINDOWSDL2_H +#define LL_LLWINDOWSDL2_H + +// Simple Directmedia Layer (http://libsdl.org/) implementation of LLWindow class + +#include "llwindow.h" +#include "lltimer.h" + +#include "SDL2/SDL.h" +#include "SDL2/SDL_endian.h" + +#if LL_X11 +// get X11-specific headers for use in low-level stuff like copy-and-paste support +#include "SDL2/SDL_syswm.h" +#endif + +// AssertMacros.h does bad things. +#include "fix_macros.h" +#undef verify +#undef require + + +class LLWindowSDL : public LLWindow +{ +public: + /*virtual*/ void show(); + /*virtual*/ void hide(); + /*virtual*/ void close(); + /*virtual*/ BOOL getVisible(); + /*virtual*/ BOOL getMinimized(); + /*virtual*/ BOOL getMaximized(); + /*virtual*/ BOOL maximize(); + /*virtual*/ void minimize(); + /*virtual*/ void restore(); + /*virtual*/ BOOL getFullscreen(); + /*virtual*/ BOOL getPosition(LLCoordScreen *position); + /*virtual*/ BOOL getSize(LLCoordScreen *size); + /*virtual*/ BOOL getSize(LLCoordWindow *size); + /*virtual*/ BOOL setPosition(LLCoordScreen position); + /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); + /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); + /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); + /*virtual*/ void showCursor(); + /*virtual*/ void hideCursor(); + /*virtual*/ void showCursorFromMouseMove(); + /*virtual*/ void hideCursorUntilMouseMove(); + /*virtual*/ BOOL isCursorHidden(); + /*virtual*/ void updateCursor(); + /*virtual*/ void captureMouse(); + /*virtual*/ void releaseMouse(); + /*virtual*/ void setMouseClipping( BOOL b ); + /*virtual*/ void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); + + /*virtual*/ BOOL isClipboardTextAvailable(); + /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); + /*virtual*/ BOOL copyTextToClipboard(const LLWString & src); + + /*virtual*/ BOOL isPrimaryTextAvailable(); + /*virtual*/ BOOL pasteTextFromPrimary(LLWString &dst); + /*virtual*/ BOOL copyTextToPrimary(const LLWString & src); + + /*virtual*/ void flashIcon(F32 seconds); + /*virtual*/ F32 getGamma(); + /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma + /*virtual*/ U32 getFSAASamples(); + /*virtual*/ void setFSAASamples(const U32 samples); + /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) + /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } + /*virtual*/ void processMiscNativeEvents(); + /*virtual*/ void gatherInput(); + /*virtual*/ void swapBuffers(); + /*virtual*/ void restoreGLContext() {}; + + /*virtual*/ void delayInputProcessing() { }; + + // handy coordinate space conversion routines + /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); + /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); + /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); + /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); + /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); + /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); + + /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); + /*virtual*/ F32 getNativeAspectRatio(); + /*virtual*/ F32 getPixelAspectRatio(); + /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } + + /*virtual*/ void beforeDialog(); + /*virtual*/ void afterDialog(); + + /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b); + + /*virtual*/ void *getPlatformWindow(); + /*virtual*/ void bringToFront(); + + /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); + /*virtual*/ void openFile(const std::string& file_name); + + /*virtual*/ void setTitle(const std::string& title); + + static std::vector getDynamicFallbackFontList(); + + // Not great that these are public, but they have to be accessible + // by non-class code and it's better than making them global. +#if LL_X11 + Window mSDL_XWindowID; + Display *mSDL_Display; +#endif + void (*Lock_Display)(void); + void (*Unlock_Display)(void); + +#if LL_GTK + // Lazily initialize and check the runtime GTK version for goodness. + static bool ll_try_gtk_init(void); +#endif // LL_GTK + +#if LL_X11 + static Window get_SDL_XWindowID(void); + static Display* get_SDL_Display(void); +#endif // LL_X11 + +protected: + LLWindowSDL(LLWindowCallbacks* callbacks, + const std::string& title, int x, int y, int width, int height, U32 flags, + BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl, + //BOOL ignore_pixel_depth, U32 fsaa_samples); + BOOL ignore_pixel_depth, U32 fsaa_samples, BOOL useLegacyCursors); // Legacy cursor setting from main program + ~LLWindowSDL(); + + /*virtual*/ BOOL isValid(); + /*virtual*/ LLSD getNativeKeyData(); + + //void initCursors(); + void initCursors(BOOL useLegacyCursors); // Legacy cursor setting from main program + void quitCursors(); + void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); + + // Changes display resolution. Returns true if successful + BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + + // Go back to last fullscreen display resolution. + BOOL setFullscreenResolution(); + + BOOL shouldPostQuit() { return mPostQuit; } + +protected: + // + // Platform specific methods + // + + // create or re-create the GL context/window. Called from the constructor and switchContext(). + BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync); + void destroyContext(); + void setupFailure(const std::string& text, const std::string& caption, U32 type); + void fixWindowSize(void); + U32 SDLCheckGrabbyKeys(U32 keysym, BOOL gain); + BOOL SDLReallyCaptureInput(BOOL capture); + + // + // Platform specific variables + // + U32 mGrabbyKeyFlags; + int mReallyCapturedCount; + + SDL_Window* mWindow; + SDL_Surface* mSurface; + SDL_GLContext mContext; + SDL_Cursor* mSDLCursors[UI_CURSOR_COUNT]; + + std::string mWindowTitle; + double mOriginalAspectRatio; + BOOL mNeedsResize; // Constructor figured out the window is too big, it needs a resize. + LLCoordScreen mNeedsResizeSize; + F32 mOverrideAspectRatio; + F32 mGamma; + U32 mFSAASamples; + + int mSDLFlags; + + int mHaveInputFocus; /* 0=no, 1=yes, else unknown */ + int mIsMinimized; /* 0=no, 1=yes, else unknown */ + + friend class LLWindowManager; + +private: +#if LL_X11 + void x11_set_urgent(BOOL urgent); + BOOL mFlashing; + LLTimer mFlashTimer; +#endif //LL_X11 + + U32 mKeyVirtualKey; + U32 mKeyModifiers; + std::string mInputType; + + BOOL mUseLegacyCursors; // Legacy cursor setting from main program + +public: +#if LL_X11 + static Display* getSDLDisplay(); + LLWString const& getPrimaryText() const { return mPrimaryClipboard; } + LLWString const& getSecondaryText() const { return mSecondaryClipboard; } + void clearPrimaryText() { mPrimaryClipboard.clear(); } + void clearSecondaryText() { mSecondaryClipboard.clear(); } +private: + void tryFindFullscreenSize( int &aWidth, int &aHeight ); + void initialiseX11Clipboard(); + + bool getSelectionText(Atom selection, LLWString& text); + bool getSelectionText( Atom selection, Atom type, LLWString &text ); + + bool setSelectionText(Atom selection, const LLWString& text); +#endif + LLWString mPrimaryClipboard; + LLWString mSecondaryClipboard; +}; + + +class LLSplashScreenSDL : public LLSplashScreen +{ +public: + LLSplashScreenSDL(); + virtual ~LLSplashScreenSDL(); + + /*virtual*/ void showImpl(); + /*virtual*/ void updateImpl(const std::string& mesg); + /*virtual*/ void hideImpl(); +}; + +S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type); + +#endif //LL_LLWINDOWSDL_H diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index fab79b5eda..470ffff2c3 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -857,6 +857,7 @@ set(viewer_SOURCE_FILES llxmlrpctransaction.cpp noise.cpp particleeditor.cpp + permissionstracker.cpp piemenu.cpp pieseparator.cpp pieslice.cpp @@ -1630,6 +1631,7 @@ set(viewer_HEADER_FILES macmain.h noise.h particleeditor.h + permissionstracker.h piemenu.h pieseparator.h pieslice.h @@ -2205,10 +2207,15 @@ add_executable(${VIEWER_BINARY_NAME} ) if (SDL_FOUND) - set_property(TARGET ${VIEWER_BINARY_NAME} - PROPERTY COMPILE_DEFINITIONS LL_SDL=1 - ) + set_property(TARGET ${VIEWER_BINARY_NAME} + PROPERTY COMPILE_DEFINITIONS LL_SDL=1 + ) endif (SDL_FOUND) +if (SDL2_FOUND) + set_property(TARGET ${VIEWER_BINARY_NAME} + PROPERTY COMPILE_DEFINITIONS LL_SDL2=1 LL_SDL=1 + ) +endif () if (USE_BUGSPLAT) set_property(TARGET ${VIEWER_BINARY_NAME} diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index cc81d718c3..32c568aee0 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.5.5 +6.5.6 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 5c39fece1b..67d17b6bce 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -20985,7 +20985,7 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0.0 - StarLightShowMapDetails + FSShowMapDetails Comment Show the details panel on the side of the World Map @@ -21929,6 +21929,30 @@ Change of this parameter will affect the layout of buttons in notification toast Boolean Value 0 + + CefVerboseLog + + Comment + Enable/disable CEF verbose loggingk + Persist + 1 + Type + Boolean + Value + 0 + + ResetUIScaleOnFirstRun + + Comment + Resets the UI scale factor on first run due to changed display scaling behavior + Persist + 1 + Type + Boolean + Value + 1 + Backup + 0 360CaptureUseInterestListCap @@ -22007,30 +22031,19 @@ Change of this parameter will affect the layout of buttons in notification toast Value 3 - CefVerboseLog - - Comment - Enable/disable CEF verbose loggingk - Persist - 1 - Type - Boolean - Value - 0 - - ResetUIScaleOnFirstRun - - Comment - Resets the UI scale factor on first run due to changed display scaling behavior - Persist - 1 - Type - Boolean - Value - 1 - Backup - 0 - + MFAHash + + Comment + Override MFA state hash for authentication + Persist + 0 + Type + String + Value + + Backup + 0 + FSShowServerVersionChangeNotice Comment @@ -24559,19 +24572,6 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 - FSLatencyOneTimeFixRun - - Comment - One time fix has run for this install for script dialog colors on Latency - Persist - 1 - HideFromEditor - 1 - Type - Boolean - Value - 0 - FSUseCtrlShout Comment diff --git a/indra/newview/app_settings/settings_latency.xml b/indra/newview/app_settings/settings_latency.xml deleted file mode 100644 index 49d7d0f677..0000000000 --- a/indra/newview/app_settings/settings_latency.xml +++ /dev/null @@ -1,774 +0,0 @@ - - - - ShowNetStats - - Comment - Show the Status Indicators for the Viewer and Network Usage in the Status Overlay. - Persist - 1 - Type - Boolean - Value - 1 - - - OpenSidePanelsInFloaters - - Comment - Open Panels in Floaters - Type - Boolean - Value - 1 - - - FSShowMouselookInstructions - - Comment - If true, instructions about leaving Mouseview are displayed. - Persist - 1 - Type - Boolean - Value - 0 - - - FSColorClienttags - - Comment - Color Client tags by: 0=Off, 1=Single color per Viewer, 2=User defined color (one color per UUID), 3=New Tagsystem Color - Persist - 1 - Type - U32 - Value - 2 - - - ShowRadarMinimap - - Comment - Toggle visibility of the embedded minimap in the radar panel - Persist - 1 - Type - Boolean - Value - 0 - - - FSUseNearbyChatConsole - - Comment - Display popup chat embedded into the read-only world console (v1-style) instead of overlayed floaters (v2-style) - Persist - 1 - Type - Boolean - Value - 1 - - - ShowScriptDialogsTopRight - - Comment - Show script llDialog floaters always in the top right corner of the screen. - Persist - 1 - Type - Boolean - Value - 1 - - - EnableGroupChatPopups - - Comment - Enable Incoming Group Chat Popups - Persist - 1 - Type - Boolean - Value - 0 - - - EnableIMChatPopups - - Comment - Enable Incoming IM Chat Popups - Persist - 1 - Type - Boolean - Value - 0 - - - PlainTextChatHistory - - Comment - Enable/Disable plain text chat history style - Persist - 1 - Type - Boolean - Value - 1 - - - ShowChatMiniIcons - - Comment - Toggles the display of mini icons in chat history - Persist - 1 - Type - Boolean - Value - 0 - - - FSChatWindow - - Comment - Show chat in multiple windows(by default) or in one multi-tabbed window(requires restart) - Persist - 1 - Type - S32 - Value - 1 - - - FSUseWebProfiles - - Comment - Shows web profiles instead of the v1-style profile floater - Persist - 1 - Type - Boolean - Value - 0 - - - FSFolderViewItemHeight - - Comment - Controls the height of folder items, for instance in inventory - Persist - 1 - Type - S32 - Value - 18 - - - ShowGroupNoticesTopRight - - Comment - Show group notifications to the top right corner of the screen. - Persist - 1 - Type - Boolean - Value - 1 - - - FSConsoleClassicDrawMode - - Comment - Enables classic console draw mode (single background block over all lines with width of the longest line) - Persist - 1 - Type - Boolean - Value - 1 - - - ResetViewTurnsAvatar - - Comment - This option keeps the camera direction and turns the avatar when Reset View is selected (hit ESC key). - Persist - 1 - Type - Boolean - Value - 1 - - - FSTrimLegacyNames - - Comment - Trim "Resident" from Legacy Names - Persist - 1 - Type - Boolean - Value - 0 - - - FSPaymentInfoInChat - - Comment - If true, L$ balance changes will be shown in nearby chat instead of toasts. - Persist - 1 - Type - Boolean - Value - 1 - - - FSShowInboxFolder - - Comment - If enabled, the Received Items folder aka Inbox is shown in the inventory as folder. - Persist - 1 - Type - Boolean - Value - 1 - - - FSUseLegacyInventoryAcceptMessages - - Comment - If enabled, the viewer will send accept/decline response for inventory offers after the according button has been pressed and not if the item has been received at the receiver's inventory already. - Persist - 1 - Type - Boolean - Value - 1 - - - FSLogImToChatConsole - - Comment - Defines if IM notifications should be sent to the nearby chat console (v1-style) or toasts (v2-style). - Persist - 1 - Type - Boolean - Value - 1 - - - FSLogGroupImToChatConsole - - Comment - Defines if group IM notifications should be sent to the nearby chat console (v1-style) or toasts (v2-style). - Persist - 1 - Type - Boolean - Value - 1 - - - FSDisableIMChiclets - - Comment - If enabled, Firestorm will not show any group / IM chat chiclets (notifications envelope and sum of IMs will remain on the screen). - Persist - 1 - Type - Boolean - Value - 1 - - - FSShowGroupNameLength - - Comment - Max length of group name to be printed in chat (-1 for full group name, 0 for disabled). - Persist - 1 - Type - S32 - Value - -1 - - - FSUseStandalonePlaceDetailsFloater - - Comment - If enabled, Firestorm will use a standalone floater for each landmark details, teleport history details and parcel details view. - Persist - 1 - Type - Boolean - Value - 1 - - - FSUseStandaloneTeleportHistoryFloater - - Comment - If enabled, Firestorm will use a standalone floater for the teleport history view. - Persist - 1 - Type - Boolean - Value - 1 - - - FSUseStandaloneBlocklistFloater - - Comment - If enabled, Firestorm will use a standalone floater for the blocklist. - Persist - 1 - Type - Boolean - Value - 1 - - - FSEnableVolumeControls - - Comment - If true, Firestorm will show volume controls (sounds, media, stream) in upper right corner of the screen. Useful, if skin already has its own controls. - Persist - 1 - Type - Boolean - Value - 0 - - - - - - ChatConsoleFontSize - - Persist - 1 - Comment - Size of chat text in chat console (0 to 3, small to huge) - Type - S32 - Value - 1 - - - ChatOnlineNotification - - Persist - 1 - Comment - Provide notifications for when friend log on and off of SL - Type - Boolean - Value - 1 - - - OnlineOfflinetoNearbyChat - - Persist - 1 - Comment - Send online/offline notifications to Nearby Chat panel (v1-style behavior) - Type - Boolean - Value - 1 - - - OnlineOfflinetoNearbyChatHistory - - Backup - 1 - Comment - Show online/offline notifications only in chat history - Type - Boolean - Value - 1 - - - FSColorUsername - - Persist - 1 - Comment - Color username distinctly from the rest of the tag - Type - Boolean - Value - 1 - - - NameTagShowFriends - - Persist - 1 - Comment - Highlight the name tags of your friends - Type - Boolean - Value - 1 - - - NameTagShowUsernames - - Persist - 1 - Comment - Show usernames in avatar name tags - Type - Boolean - Value - 1 - - - FSTagShowDistanceColors - - Persist - 1 - Comment - If enabled, color other avatars' nametags based on their distance - Type - Boolean - Value - 0 - - - FSTagShowDistance - - Persist - 1 - Comment - If enabled, show distance to other avatars in their nametag. - Type - Boolean - Value - 0 - - - LetterKeysAffectsMovementNotFocusChatBar - - Persist - 1 - Comment - When printable characters keys (possibly with Shift held) are pressed, the chat bar does not take focus and movement is affected instead (WASD etc.) - Type - Boolean - Value - 1 - - - AutohideChatBar - - Persist - 1 - Comment - Hide the chat bar from the bottom button bar and only show it as an overlay when needed. - Type - Boolean - Value - 1 - - - MiniMapRotate - - Persist - 1 - Comment - Rotate miniature world map to avatar direction - Type - Boolean - Value - 0 - - - ShowNavbarFavoritesPanel - - Persist - 1 - Comment - Show/hide navigation bar favorites panel - Type - Boolean - Value - 0 - - - ShowSearchTopBar - - Persist - 1 - Comment - Toggles whether the search field is displayed at the top of the viewer - Type - Boolean - Value - 0 - - - SkinCurrent - - Persist - 1 - Comment - The currently selected skin. - Type - String - Value - latency - - - SkinCurrentTheme - - Persist - 1 - Comment - The selected theme for the current skin. - Type - String - Value - - - - FSSkinCurrentReadableName - - Persist - 1 - Comment - The readable name of the currently selected skin. - Type - String - Value - Latency - - - FSSkinCurrentThemeReadableName - - Persist - 1 - Comment - The readable name of the selected theme for the current skin. - Type - String - Value - Extra Plain - - - FSLegacyMinimize - - Persist - 1 - Comment - Minimize floaters to bottom left instead of top left. - Type - Boolean - Value - 1 - - - FSGroupNotifyNoTransparency - - Persist - 1 - Comment - If true, group notices will be shown opaque and ignore the floater opacity settings. - Type - Boolean - Value - 1 - - - FSScriptDialogNoTransparency - - Persist - 1 - Comment - If true, script dialogs will be shown opaque and ignore the floater opacity settings. - Type - Boolean - Value - 1 - - - NotificationCanEmbedInIM - - Persist - 1 - Comment - Controls notification panel embedding in IMs (0 = default, 1 = focused, 2 = never) - Type - S32 - Value - 2 - - - FSBetterGroupNoticesToIMLog - - Persist - 1 - Comment - Improved logging of group notices to group IM log. - Type - Boolean - Value - 1 - - - FSFadeGroupNotices - - Persist - 1 - Comment - Fade group notices. (V3 default: true) - Type - Boolean - Value - 0 - - - FSSortFSFoldersToTop - - Persist - 1 - Comment - Sorts the #FS and #RLV folders to the top like system folders. - Type - Boolean - Value - 0 - - - - MediaFilterSinglePrompt - - Persist - 1 - Comment - Use a single legacy style dialog for media filter prompt, instead of two seperate allow/deny and whitelist/blacklist prompts. - Type - Boolean - Value - 1 - - - FSEmphasizeShoutWhisper - - Persist - 1 - Comment - Enables bolding shouted chat and italicizing whispered chat - Type - Boolean - Value - 0 - - - FSLegacyRadarFriendColoring - - Persist - 1 - Comment - Use old style for friends on the radar. Uses same color as minimap. - Type - Boolean - Value - 1 - - - FSLegacyRadarLindenColoring - - Persist - 1 - Comment - Color Lindens on the radar the same as the minimap. - Type - Boolean - Value - 1 - - - RenderHiddenSelections - - Persist - 1 - Comment - Show selection lines on objects that are behind other objects - Type - Boolean - Value - 1 - - - RadarNameFormat - - Persist - 1 - Comment - 0=DisplayName,1=Username,2=Displayname/Username,3=Username/Displayname - Type - U32 - Value - 2 - - - FSFlashOnMessage - - Persist - 1 - Comment - Flash/Bounce the app icon when a new message is recieved and Firestorm is not in focus - Type - Boolean - Value - 1 - - - PlayModeUISndScriptFloaterOpen - - Persist - 1 - Comment - Holds state for Prefs > Sound/Media > UI Sounds - UISndScriptFloaterOpen. - Type - Boolean - Value - 0 - - - PieMenuPopupFontEffect - - Comment - If enabled, the labels in the pie menu slices are affected by the popup effect (they move into position). - Persist - 1 - Type - Boolean - Value - 0 - - - PieMenuOuterRingShade - - Comment - If enabled, a shade around the outside of the pie menu will be drawn, adding a further visualization of sub menus. - Persist - 1 - Type - Boolean - Value - 0 - - - diff --git a/indra/newview/app_settings/settings_v3.xml b/indra/newview/app_settings/settings_v3.xml index 6c89031e12..e6a1caebef 100644 --- a/indra/newview/app_settings/settings_v3.xml +++ b/indra/newview/app_settings/settings_v3.xml @@ -80,7 +80,7 @@ Type String Value - starlight + firestorm SkinCurrentTheme @@ -106,7 +106,7 @@ Type String Value - Starlight + Firestorm FSSkinCurrentThemeReadableName diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl index 99bcba797b..07ba7f5bb7 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl @@ -54,6 +54,9 @@ vec3 fullbrightScaleSoftClip(vec3 light); uniform float minimum_alpha; #endif +// Fullbright fog fix w/ gamma 0 workaround. +uniform float gamma; + void main() { #ifdef HAS_DIFFUSE_LOOKUP @@ -72,9 +75,15 @@ void main() #endif color.rgb *= vertex_color.rgb; - // Fullbright fog fix - color.rgb = fullbrightAtmosTransport(color.rgb); - color.rgb = fullbrightScaleSoftClip(color.rgb); + // Fullbright fog fix w/ gamma 0 workaround. + // color.rgb = fullbrightAtmosTransport(color.rgb); + // color.rgb = fullbrightScaleSoftClip(color.rgb); + if(gamma != 0.) + { + color.rgb = fullbrightAtmosTransport(color.rgb); + color.rgb = fullbrightScaleSoftClip(color.rgb); + } + // Fullbright fog fix w/ gamma 0 workaround. #ifdef WATER_FOG vec3 pos = vary_position; diff --git a/indra/newview/desktopnotifierlinux.cpp b/indra/newview/desktopnotifierlinux.cpp index f3b2508409..5d390178c8 100644 --- a/indra/newview/desktopnotifierlinux.cpp +++ b/indra/newview/desktopnotifierlinux.cpp @@ -289,7 +289,7 @@ void DesktopNotifierLinux::showNotification( const std::string& notification_tit m_pLibNotify->mNotificationUpdate( m_pNotification,(gchar*)notification_title.c_str(), (gchar*)notification_message.c_str(), m_strIcon.c_str() ); - m_pLibNotify->mNotificationSetUrgency( m_pNotification, NOTIFY_URGENCY_LOW ); + m_pLibNotify->mNotificationSetUrgency( m_pNotification, NOTIFY_URGENCY_NORMAL ); m_pLibNotify->mNotificationSetCategory( m_pNotification, ( gchar* )notification_type.c_str() ); m_pLibNotify->mNotificationSetTimeout( m_pNotification, NOTIFICATION_TIMEOUT_MS ); // NotifyOSD ignores this, sadly. diff --git a/indra/newview/fscommon.cpp b/indra/newview/fscommon.cpp index b87fd79ef6..f000dd3040 100644 --- a/indra/newview/fscommon.cpp +++ b/indra/newview/fscommon.cpp @@ -492,7 +492,7 @@ bool FSCommon::isDefaultTexture(const LLUUID& asset_id) bool FSCommon::isLegacySkin() { std::string current_skin = gSavedSettings.getString("FSInternalSkinCurrent"); - return (current_skin == "Vintage" || current_skin == "Latency"); + return (current_skin == "Vintage"); } bool FSCommon::isFilterEditorKeyCombo(KEY key, MASK mask) diff --git a/indra/newview/fsfloaterim.cpp b/indra/newview/fsfloaterim.cpp index 591d76f91e..528d859aa2 100644 --- a/indra/newview/fsfloaterim.cpp +++ b/indra/newview/fsfloaterim.cpp @@ -411,14 +411,7 @@ void FSFloaterIM::sendMsgFromInputEditor(EChatType type) static LLCachedControl FSInternalSkinCurrent(gSavedSettings, "FSInternalSkinCurrent"); std::string skin_indicator(FSInternalSkinCurrent); LLStringUtil::toLower(skin_indicator); - if (skin_indicator == "starlight cui") - { - skin_indicator = "sc"; // Separate "s" (StarLight) from "sc" (StarLight CUI) - } - else - { - skin_indicator = skin_indicator.substr(0, 1); // "FS 4.4.1f os", "FS 4.4.1v", "FS 4.4.1a", "FS 4.4.1s os", "FS 4.4.1m os" etc. - } + skin_indicator = skin_indicator.substr(0, 1); // "FS 4.4.1f os", "FS 4.4.1v", "FS 4.4.1a", "FS 4.4.1s os", "FS 4.4.1m os" etc. // //Address size check diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 2c88642583..c64fec057b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3464,17 +3464,6 @@ bool LLAppViewer::initConfiguration() gLastRunVersion = gSavedSettings.getString("LastRunVersion"); loadColorSettings(); - - // One time fix for Latency - if ((gLastRunVersion != LLVersionInfo::getInstance()->getChannelAndVersion()) && (gSavedSettings.getString("SkinCurrent") == "latency") && !gSavedSettings.getBOOL("FSLatencyOneTimeFixRun")) - { - LL_INFOS() << "FSLatencyOneTimeFix: Fixing script dialog colors." << LL_ENDL; - // Replace previously saved script dialog colors with new defaults, which happen to be the same as the group notice colors - LLUIColorTable::instance().setColor("ScriptDialog", LLUIColorTable::instance().getColor("GroupNotifyDialogBG", LLColor4::grey4)); - LLUIColorTable::instance().setColor("ScriptDialogFg", LLUIColorTable::instance().getColor("GroupNotifyTextColor", LLColor4::white)); - } - gSavedSettings.setBOOL("FSLatencyOneTimeFixRun", TRUE); - // // Let anyone else who cares know that we've populated our settings // variables. diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index a92cea23c6..517ae8fbbd 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -5209,34 +5209,6 @@ void LLPanelPreferenceSkins::apply() gSavedSettings.setBOOL("ResetToolbarSettings", TRUE); } - if (m_Skin == "starlight" || m_Skin == "starlightcui") - { - std::string noteMessage; - - if (gSavedSettings.getBOOL("ShowMenuBarLocation")) - { - noteMessage = LLTrans::getString("skin_defaults_starlight_location"); - gSavedSettings.setBOOL("ShowMenuBarLocation", FALSE); - } - - if (!gSavedSettings.getBOOL("ShowNavbarNavigationPanel")) - { - if (!noteMessage.empty()) - { - noteMessage += "\n"; - } - noteMessage += LLTrans::getString("skin_defaults_starlight_navbar"); - gSavedSettings.setBOOL("ShowNavbarNavigationPanel", TRUE); - } - - if (!noteMessage.empty()) - { - LLSD args; - args["MESSAGE"] = noteMessage; - LLNotificationsUtil::add("SkinDefaultsChangeSettings", args, LLSD(), boost::bind(&LLPanelPreferenceSkins::showSkinChangeNotification, this)); - return; - } - } // showSkinChangeNotification(); diff --git a/indra/newview/llfollowcam.cpp b/indra/newview/llfollowcam.cpp index c2ea3b07c1..4a65e8c2dc 100644 --- a/indra/newview/llfollowcam.cpp +++ b/indra/newview/llfollowcam.cpp @@ -29,6 +29,8 @@ #include "llfollowcam.h" #include "llagent.h" +#include "permissionstracker.h" + //------------------------------------------------------- // constants //------------------------------------------------------- @@ -829,11 +831,13 @@ void LLFollowCamMgr::setCameraActive( const LLUUID& source, bool active ) if (found_it != mParamStack.end()) { mParamStack.erase(found_it); + PermissionsTracker::instance().removePermissionsEntry(source, PermissionsTracker::PERM_FOLLOWCAM); } // put on top of stack if(active) { mParamStack.push_back(params); + PermissionsTracker::instance().addPermissionsEntry(source, PermissionsTracker::PERM_FOLLOWCAM); } } @@ -843,6 +847,8 @@ void LLFollowCamMgr::removeFollowCamParams(const LLUUID& source) LLFollowCamParams* params = getParamsForID(source); mParamMap.erase(source); delete params; + + PermissionsTracker::instance().removePermissionsEntry(source, PermissionsTracker::PERM_FOLLOWCAM); } bool LLFollowCamMgr::isScriptedCameraSource(const LLUUID& source) diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index be72efd354..3b694803ad 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -61,6 +61,7 @@ #include "lltrans.h" #include +#include #include const S32 LOGIN_MAX_RETRIES = 0; // Viewer should not autmatically retry login @@ -239,8 +240,9 @@ void LLLoginInstance::constructAuthParams(LLPointer user_credentia request_params["id0"] = mSerialNumber; request_params["host_id"] = gSavedSettings.getString("HostID"); request_params["extended_errors"] = true; // request message_id and message_args + request_params["token"] = ""; - // log request_params _before_ adding the credentials + // log request_params _before_ adding the credentials or sensitive MFA hash data LL_DEBUGS("LLLogin") << "Login parameters: " << LLSDOStreamer(request_params) << LL_ENDL; // Copy the credentials into the request after logging the rest @@ -253,6 +255,33 @@ void LLLoginInstance::constructAuthParams(LLPointer user_credentia request_params[it->first] = it->second; } + std::string mfa_hash = gSavedSettings.getString("MFAHash"); //non-persistent to enable testing + std::string grid(LLGridManager::getInstance()->getGridId()); + std::string user_id = user_credential->userID(); + if (gSecAPIHandler) + { + if (mfa_hash.empty()) + { + // normal execution, mfa_hash was not set from debug setting so load from protected store + LLSD data_map = gSecAPIHandler->getProtectedData("mfa_hash", grid); + if (data_map.isMap() && data_map.has(user_id)) + { + mfa_hash = data_map[user_id].asString(); + } + } + else + { + // SL-16888 the mfa_hash is being overridden for testing so save it for consistency for future login requests + gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, mfa_hash); + } + } + else + { + LL_WARNS() << "unable to access protected store for mfa_hash" << LL_ENDL; + } + + request_params["mfa_hash"] = mfa_hash; + // Specify desired timeout/retry options LLSD http_params; F32 srv_timeout = llclamp(gSavedSettings.getF32("LoginSRVTimeout"), LOGIN_SRV_TIMEOUT_MIN, LOGIN_SRV_TIMEOUT_MAX); @@ -425,6 +454,38 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) boost::bind(&LLLoginInstance::syncWithUpdater, this, resp, _1, _2)); } } + else if(reason_response == "mfa_challenge") + { + LL_DEBUGS("LLLogin") << " MFA challenge" << LL_ENDL; + + if (gViewerWindow) + { + gViewerWindow->setShowProgress(FALSE, FALSE); + } + + LLSD args(llsd::map( "MESSAGE", LLTrans::getString(response["message_id"]) )); + LLSD payload; + LLNotificationsUtil::add("PromptMFAToken", args, payload, [=](LLSD const & notif, LLSD const & response) { + bool continue_clicked = response["continue"].asBoolean(); + std::string token = response["token"].asString(); + LL_DEBUGS("LLLogin") << "PromptMFAToken: response: " << response << " continue_clicked" << continue_clicked << LL_ENDL; + + // strip out whitespace - SL-17034/BUG-231938 + token = boost::regex_replace(token, boost::regex("\\s"), ""); + + if (continue_clicked && !token.empty()) + { + LL_INFOS("LLLogin") << "PromptMFAToken: token submitted" << LL_ENDL; + + // Set the request data to true and retry login. + mRequestData["params"]["token"] = token; + reconnect(); + } else { + LL_INFOS("LLLogin") << "PromptMFAToken: no token, attemptComplete" << LL_ENDL; + attemptComplete(); + } + }); + } else if( reason_response == "key" || reason_response == "presence" || reason_response == "connect" diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 1d6f8b3270..7d5fe8af48 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1909,7 +1909,11 @@ void LLModelPreview::updateStatusMessages() NOHAVOK = 1, DEGENERATE = 2, TOOMANYHULLS = 4, - TOOMANYVERTSINHULL = 8 +// fIRE-31602 thin mesh physics warning + // TOOMANYVERTSINHULL = 8 + TOOMANYVERTSINHULL = 8, + TOOTHIN = 16 +// }; assert_main_thread(); @@ -2018,10 +2022,22 @@ void LLModelPreview::updateStatusMessages() mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; } +// fIRE-31602 thin mesh physics warning + static const float CONVEXIFICATION_SIZE_MESH {0.5}; + auto smallest_axis = llmin(mPreviewScale.mV[0], mPreviewScale.mV[1]); + smallest_axis = llmin(smallest_axis, mPreviewScale.mV[2]); + smallest_axis *= 2.f; + if (smallest_axis < CONVEXIFICATION_SIZE_MESH) + { + has_physics_error |= PhysicsError::TOOTHIN; + } +// mPhysics.mHull.empty()) @@ -2268,6 +2284,14 @@ void LLModelPreview::updateStatusMessages() LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Error"); physStatusIcon->setImage(img); } +// fIRE-31602 thin mesh physics warning + else if (has_physics_error & PhysicsError::TOOTHIN) + { + mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_too_thin")); + LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning"); + physStatusIcon->setImage(img); + } +// else if (has_physics_error & PhysicsError::NOHAVOK) { mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_no_havok")); diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 6be25911db..1912e15bf5 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -691,7 +691,7 @@ void LLPanelStandStopFlying::reparent(LLFloaterMove* move_view) // Attach to movement controls. parent->removeChild(this); - // FIRE-9636: Resizable movement controls (for all skins except Starlight/CUI) + // FIRE-9636: Resizable movement controls //move_view->addChild(this); LLView* modes_container = move_view->findChildView("modes_container"); if (modes_container) diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index 95ad1e79ba..03d7068c7c 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -485,6 +485,9 @@ public: const std::string& data_id, const std::string& map_elem)=0; + // ensure protected store's map is written to storage + virtual void syncProtectedMap() = 0; + public: virtual LLPointer createCredential(const std::string& grid, const LLSD& identifier, diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 72c7c9cde2..63e97d1ad7 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -1621,6 +1621,11 @@ void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type, } } +void LLSecAPIBasicHandler::syncProtectedMap() +{ + // TODO - consider unifing these functions + _writeProtectedData(); +} // // Create a credential object from an identifier and authenticator. credentials are // per credential name (was: grid). diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index df53e01524..47fa724996 100644 --- a/indra/newview/llsechandler_basic.h +++ b/indra/newview/llsechandler_basic.h @@ -278,6 +278,9 @@ public: const std::string& data_id, const std::string& map_elem); + // ensure protected store's map is written to storage + virtual void syncProtectedMap(); + // credential management routines virtual LLPointer createCredential(const std::string& credName, diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 514a05abbb..a51de50e1a 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -43,6 +43,10 @@ # include "llaudioengine_fmodstudio.h" #endif +#ifdef LL_SDL2 +#include "llaudioengine_sdl2.h" +#endif + #ifdef LL_OPENAL #include "llaudioengine_openal.h" #endif @@ -137,6 +141,7 @@ #include "llproxy.h" #include "llproductinforequest.h" #include "llqueryflags.h" +#include "llsecapi.h" #include "llselectmgr.h" #include "llsky.h" #include "llstatview.h" @@ -997,6 +1002,11 @@ bool idle_startup() } #endif +#ifdef LL_SDL2 + if( !gAudiop ) + gAudiop = new LLAudioEngineSDL2(); +#endif + #ifdef LL_OPENAL #if !LL_WINDOWS // if (NULL == getenv("LL_BAD_OPENAL_DRIVER")) @@ -1730,10 +1740,10 @@ bool idle_startup() } else { - if (reason_response != "tos") + if (reason_response != "tos" && reason_response != "mfa_challenge") { - // Don't pop up a notification in the TOS case because - // LLFloaterTOS::onCancel() already scolded the user. + // Don't pop up a notification in the TOS or MFA cases because + // the specialized floater has already scolded the user. std::string error_code; if(response.has("errorcode")) { @@ -4740,6 +4750,17 @@ bool process_login_success_response(U32 &first_sim_size_x, U32 &first_sim_size_y LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); } + + // Only save mfa_hash for future logins if the user wants their info remembered. + if(response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser") && gSavedSettings.getBOOL("RememberPassword")) + { + std::string grid(LLGridManager::getInstance()->getGridId()); + std::string user_id(gUserCredential->userID()); + gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]); + // TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically + gSecAPIHandler->syncProtectedMap(); + } + // OpenSim legacy economy support #ifdef OPENSIM if (!LLGridManager::instance().isInSecondLife()) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index a987ecec2c..a2a208ab71 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -168,6 +168,7 @@ #include "lltexturecache.h" #include "llvovolume.h" #include "particleeditor.h" +#include "permissionstracker.h" using namespace LLAvatarAppearanceDefines; @@ -5450,6 +5451,9 @@ void handle_reset_camera_angles() // Camera focus and offset with CTRL/SHIFT + Scroll wheel gSavedSettings.getControl("FocusOffsetRearView")->resetToDefault(); gSavedSettings.getControl("CameraOffsetRearView")->resetToDefault(); + + // warn the user if there is a scripted followcam active that might stop a camera reset + PermissionsTracker::instance().warnFollowcam(); } // diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index e4eea0a510..d7b64bc5c1 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -150,6 +150,7 @@ #include "llfloaterbump.h" #include "llfloaterreg.h" #include "llfriendcard.h" +#include "permissionstracker.h" // Permissions Tracker #include "tea.h" // #include "NACLantispam.h" #include "chatbar_as_cmdline.h" @@ -4733,6 +4734,8 @@ void process_object_properties(LLMessageSystem *msg, void**user_data) { explorer->requestNameCallback(msg); } + + PermissionsTracker::instance().objectPropertiesCallback(msg); } // area search diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 208d1cb041..e333d5678c 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -3147,6 +3147,7 @@ void LLVOAvatarSelf::reportAvatarRezTime() const //-- SUNSHINE CLEANUP - not clear we need any of this, may be sufficient to request server appearance in llviewermenu.cpp:handle_rebake_textures() void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug) { + if(!isAgentAvatarValid()){ return; } // Avoid force bak e on invalid avatar pointer (based on similar change by Rye) LL_INFOS() << "TAT: forced full rebake. " << LL_ENDL; for (U32 i = 0; i < mBakedTextureDatas.size(); i++) diff --git a/indra/newview/permissionstracker.cpp b/indra/newview/permissionstracker.cpp new file mode 100644 index 0000000000..db01feee27 --- /dev/null +++ b/indra/newview/permissionstracker.cpp @@ -0,0 +1,274 @@ +/** + * @file permissionstracker.cpp + * @brief Permissions Tracker implementation - Initially it's only tracking + * camera control permissions, to warn users about attachments or seats that + * took camera control permissions and might interfere with resetting the + * camera view. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2022, Zi Ree @ Second Life + * + * 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 "llagentdata.h" // for gAgentID anf gAgentSessionID +#include "llnotificationsutil.h" +#include "llslurl.h" +#include "lltrans.h" +#include "llviewermenu.h" // for handle_object_edit() +#include "llviewerregion.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" // for gObjectList +#include "llvoavatarself.h" // for gAgentAvatarp +#include "llworld.h" + +#include "permissionstracker.h" + +#define PERMISSION_ENTRY_EXPIRY_TIME 3600.0 + +PermissionsTracker::PermissionsTracker() +: LLSingleton() +{ +} + +PermissionsTracker::~PermissionsTracker() +{ +} + +void PermissionsTracker::addPermissionsEntry(const LLUUID& source_id, PermissionsTracker::PERM_TYPE permission_type) +{ + // find out if this is a new entry in the list + if (mPermissionsList.find(source_id) == mPermissionsList.end()) + { + LL_DEBUGS("PermissionsTracker") << "Creating list entry for source " << source_id << LL_ENDL; + mPermissionsList[source_id].objectName = LLTrans::getString("LoadingData"); + + // find out if the object is still in reach + LLViewerObject* vo = gObjectList.findObject(source_id); + if (!vo) + { + mPermissionsList[source_id].objectName = LLTrans::getString("ObjectOutOfRange"); + } + else + { + mPermissionsList[source_id].attachmentID = vo->getAttachmentItemID(); + LL_DEBUGS("PermissionsTracker") << "Requesting ObjectProperties for source " << source_id << LL_ENDL; + + // remember which object names we already requested + mRequestedIDs.push_back(source_id); + + // send a request out to get this object's details + LLMessageSystem* msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_ObjectSelect); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgentID); + msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, vo->getLocalID()); + msg->sendReliable(gAgentAvatarp->getRegion()->getHost()); + + msg->newMessageFast(_PREHASH_ObjectDeselect); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgentID); + msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, vo->getLocalID()); + msg->sendReliable(gAgentAvatarp->getRegion()->getHost()); + } + } + + LL_DEBUGS("PermissionsTracker") << "Adding permission type " << permission_type << " to source " << source_id << LL_ENDL; + mPermissionsList[source_id].type |= permission_type; + mPermissionsList[source_id].time = LLDate(LLTimer::getTotalSeconds()); + + purgePermissionsEntries(); +} + +void PermissionsTracker::removePermissionsEntry(const LLUUID& source_id, PermissionsTracker::PERM_TYPE permission_type) +{ + if (mPermissionsList.find(source_id) == mPermissionsList.end()) + { + LL_DEBUGS("PermissionsTracker") << "Could not find list entry for source " << source_id << LL_ENDL; + return; + } + + LL_DEBUGS("PermissionsTracker") << "Removing permissions type " << permission_type << " from source " << source_id << LL_ENDL; + mPermissionsList[source_id].type &= ~permission_type; + mPermissionsList[source_id].time = LLDate(LLTimer::getTotalSeconds()); + + purgePermissionsEntries(); +} + +void PermissionsTracker::purgePermissionsEntries() +{ + F64 expiry_time = LLDate(LLTimer::getTotalSeconds()).secondsSinceEpoch() - PERMISSION_ENTRY_EXPIRY_TIME; + + auto it = mPermissionsList.begin(); + while (it != mPermissionsList.end()) + { + if (it->second.type == PERM_TYPE::PERM_NONE && it->second.time.secondsSinceEpoch() < expiry_time) + { + LL_DEBUGS("PermissionsTracker") << "Erasing list entry for source " << it->first << LL_ENDL; + it = mPermissionsList.erase(it); + } + else + { + ++it; + } + } +} + +void PermissionsTracker::warnFollowcam() +{ + std::string followcamList; + for (auto entry : mPermissionsList) + { + if (entry.second.type & PermissionsTracker::PERM_FOLLOWCAM) + { + if (entry.second.attachmentID.notNull()) + { + std::string attachment_point = "???"; + gAgentAvatarp->getAttachedPointName(entry.second.attachmentID, attachment_point); + + LLSD args; + args["ATTACHMENT_POINT"] = attachment_point; + + std::string verb = "select?name=" + LLURI::escape(entry.second.objectName); + followcamList += LLSLURL("inventory", entry.second.attachmentID, verb.c_str()).getSLURLString() + " " + + LLTrans::getString("WornOnAttachmentPoint", args) + "\n"; + } + else + { + followcamList += LLSLURL("objectim", entry.first, "").getSLURLString() + + "?name=" + LLURI::escape(entry.second.objectName) + + "&owner=" + entry.second.ownerID.asString(); + + LLSD args; + std::string slurl = args["slurl"].asString(); + if (slurl.empty()) + { + LLViewerRegion* region = LLWorld::instance().getRegionFromPosAgent(gAgentAvatarp->getPositionAgent()); + if(region) + { + LLSLURL region_slurl(region->getName(), gAgentAvatarp->getPositionAgent()); + slurl = region_slurl.getLocationString(); + } + } + + followcamList += "&slurl=" + LLURI::escape(slurl) + "\n"; + } + } + } + + if (followcamList.empty()) + { + return; + } + + LLSD args; + args["SOURCES"] = followcamList; + LLNotificationsUtil::add("WarnScriptedCamera", args); +} + +void PermissionsTracker::objectPropertiesCallback(LLMessageSystem* msg) +{ + LL_DEBUGS("PermissionsTracker") << "Received ObjectProperties message." << LL_ENDL; + + // if we weren't looking for any IDs, ignore this callback + if (mRequestedIDs.empty()) + { + LL_DEBUGS("PermissionsTracker") << "No objects in request list." << LL_ENDL; + return; + } + + // we might have received more than one answer in one block + S32 num = msg->getNumberOfBlocksFast(_PREHASH_ObjectData); + for (S32 index = 0; index < num; ++index) + { + LLUUID source_id; + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id, index); + + auto iter = std::find(mRequestedIDs.begin(), mRequestedIDs.end(), source_id); + // if this is one of the objects we were looking for, process the data + if (iter != mRequestedIDs.end()) + { + // get the name of the object + std::string object_name; + msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, object_name, index); + + LLUUID object_owner; + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, object_owner, index); + + LL_DEBUGS("PermissionsTracker") << "Received object name " << object_name + << " and owner " << object_owner.asString() << " for source " << source_id << LL_ENDL; + + // remove the object from the lookup list and add it to the known names list + mRequestedIDs.erase(iter); + + mPermissionsList[source_id].objectName = object_name; + mPermissionsList[source_id].ownerID = object_owner; + + LLAvatarName avatar_name; + if (LLAvatarNameCache::get(object_owner, &avatar_name)) + { + LL_DEBUGS("PermissionsTracker") << "Found cached entry for owner " << object_owner.asString() + << ": " << avatar_name.getCompleteName() << LL_ENDL; + mPermissionsList[source_id].ownerName = avatar_name.getCompleteName(); + } + else + { + if (mAvatarNameCacheConnections.find(object_owner) != mAvatarNameCacheConnections.end()) + { + boost::signals2::connection cb_connection = LLAvatarNameCache::get(object_owner, boost::bind(&PermissionsTracker::avatarNameCallback, this, _1, _2)); + mAvatarNameCacheConnections.insert(std::make_pair(object_owner, cb_connection)); + + LL_DEBUGS("PermissionsTracker") << "Requesting avatar name for owner " << object_owner.asString() << LL_ENDL; + } + } + } + } +} + +void PermissionsTracker::avatarNameCallback(const LLUUID& avatar_id, const LLAvatarName& avatar_name) +{ + LL_DEBUGS("PermissionsTracker") << "Received avatar name " << avatar_name.getCompleteName() << LL_ENDL; + + auto iter = mAvatarNameCacheConnections.find(avatar_id); + if (iter != mAvatarNameCacheConnections.end()) + { + if (iter->second.connected()) + { + iter->second.disconnect(); + } + mAvatarNameCacheConnections.erase(iter); + } + + for (auto entry : mPermissionsList) + { + if (entry.second.ownerID == avatar_id) + { + LL_DEBUGS("PermissionsTracker") << "Saved avatar name " << avatar_name.getCompleteName()<< " for source " << entry.first.asString() << LL_ENDL; + entry.second.ownerName = avatar_name.getCompleteName(); + } + } +} diff --git a/indra/newview/permissionstracker.h b/indra/newview/permissionstracker.h new file mode 100644 index 0000000000..0072d564e6 --- /dev/null +++ b/indra/newview/permissionstracker.h @@ -0,0 +1,86 @@ +/** + * @file permissionstracker.h + * @brief Permissions Tracker declaration + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2022, Zi Ree @ Second Life + * + * 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 PERMISSIONSTRACKER_H +#define PERMISSIONSTRACKER_H + +#include "llfloater.h" +#include "llsingleton.h" + +// -------------------------------------------------------------------------- +// PermissionsTracker: holds a list of requested script permissions to be +// referred to e.g. when trying to reset the camera view and a script is +// holding a follow cam which micht prevent it from working. +// -------------------------------------------------------------------------- + +class PermissionsTracker +: public LLSingleton +{ + LLSINGLETON(PermissionsTracker); + ~PermissionsTracker(); + + public: + enum PERM_TYPE + { + PERM_NONE = 0, + PERM_FOLLOWCAM = 1, + }; + + struct PermissionsEntry + { + LLUUID ownerID; // agent who owns the requesting object + LLUUID attachmentID; // attachment ID in inventory for attached objects + std::string ownerName; + std::string objectName; + LLDate time; // time when the permission was granted + U32 type; // what kind of permissions were granted + }; + + std::map mPermissionsList; // UUID of the requesting object + + void addPermissionsEntry( + const LLUUID& source_id, + PermissionsTracker::PERM_TYPE permission_type); // called in llviewermessage.cpp + + void removePermissionsEntry( + const LLUUID& source_id, + PermissionsTracker::PERM_TYPE permission_type); // called in llviewermessage.cpp + + void purgePermissionsEntries(); + + void objectPropertiesCallback(LLMessageSystem* msg); + void avatarNameCallback(const LLUUID& avatar_id, const LLAvatarName& av_name); + + void warnFollowcam(); // Warn the user if a script is holding followcam parameters + + std::vector mRequestedIDs; // list of object IDs we requested named for + + typedef std::map avatar_name_cache_connection_map_t; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; +}; + +#endif // PERMISSIONSTRACKER_H diff --git a/indra/newview/skins/default/textures/skinspreview/lat_plain.jpg b/indra/newview/skins/default/textures/skinspreview/lat_plain.jpg deleted file mode 100644 index 5034294112..0000000000 Binary files a/indra/newview/skins/default/textures/skinspreview/lat_plain.jpg and /dev/null differ diff --git a/indra/newview/skins/default/textures/skinspreview/scui_dark.jpg b/indra/newview/skins/default/textures/skinspreview/scui_dark.jpg deleted file mode 100644 index 700fb235ce..0000000000 Binary files a/indra/newview/skins/default/textures/skinspreview/scui_dark.jpg and /dev/null differ diff --git a/indra/newview/skins/default/textures/skinspreview/scui_light.jpg b/indra/newview/skins/default/textures/skinspreview/scui_light.jpg deleted file mode 100644 index 2466269056..0000000000 Binary files a/indra/newview/skins/default/textures/skinspreview/scui_light.jpg and /dev/null differ diff --git a/indra/newview/skins/default/textures/skinspreview/slight_mteal.jpg b/indra/newview/skins/default/textures/skinspreview/slight_mteal.jpg deleted file mode 100644 index 211113da73..0000000000 Binary files a/indra/newview/skins/default/textures/skinspreview/slight_mteal.jpg and /dev/null differ diff --git a/indra/newview/skins/default/textures/skinspreview/slight_nblue.jpg b/indra/newview/skins/default/textures/skinspreview/slight_nblue.jpg deleted file mode 100644 index 5f7adc8247..0000000000 Binary files a/indra/newview/skins/default/textures/skinspreview/slight_nblue.jpg and /dev/null differ diff --git a/indra/newview/skins/default/textures/skinspreview/slight_orange.jpg b/indra/newview/skins/default/textures/skinspreview/slight_orange.jpg deleted file mode 100644 index b20fd62082..0000000000 Binary files a/indra/newview/skins/default/textures/skinspreview/slight_orange.jpg and /dev/null differ diff --git a/indra/newview/skins/default/textures/skinspreview/slight_sblue.jpg b/indra/newview/skins/default/textures/skinspreview/slight_sblue.jpg deleted file mode 100644 index 42813e5358..0000000000 Binary files a/indra/newview/skins/default/textures/skinspreview/slight_sblue.jpg and /dev/null differ diff --git a/indra/newview/skins/default/textures/skinspreview/slight_spink.jpg b/indra/newview/skins/default/textures/skinspreview/slight_spink.jpg deleted file mode 100644 index b6e9c0ae6e..0000000000 Binary files a/indra/newview/skins/default/textures/skinspreview/slight_spink.jpg and /dev/null differ diff --git a/indra/newview/skins/default/textures/skinspreview/slight_teal.jpg b/indra/newview/skins/default/textures/skinspreview/slight_teal.jpg deleted file mode 100644 index 75f1702842..0000000000 Binary files a/indra/newview/skins/default/textures/skinspreview/slight_teal.jpg and /dev/null differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 64d32ab161..f0d8b243c6 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -834,18 +834,9 @@ with the same filename but different name - - - - - - - - - @@ -1022,16 +1013,13 @@ with the same filename but different name - - - - - - - + + + + diff --git a/indra/newview/skins/default/xui/de/floater_about.xml b/indra/newview/skins/default/xui/de/floater_about.xml index b8a174b981..65003bc4d4 100644 --- a/indra/newview/skins/default/xui/de/floater_about.xml +++ b/indra/newview/skins/default/xui/de/floater_about.xml @@ -36,8 +36,6 @@ Zusätzlicher Programmcode von: Besonderer Dank gilt unserem Firestorm-Support-Team sowie den Wiki-Autoren, Schulungsleitern und Übersetzern: -Firestorm enthält Starlight, modifiziert für Firestorm. Es ist von Einwohnern für Einwohner und hat das Ziel, eine alternative, freundlichere und hoffentlich einfacher zu bedienende Oberfläche bereitzustellen. Für weitere Details, siehe <nolink>https://wiki.secondlife.com/wiki/Viewer_Skins/Starlight</nolink>. - UI-Künstler und Designer: diff --git a/indra/newview/skins/default/xui/de/floater_model_preview.xml b/indra/newview/skins/default/xui/de/floater_model_preview.xml index 088be49dbb..dca17c52c0 100644 --- a/indra/newview/skins/default/xui/de/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/de/floater_model_preview.xml @@ -76,6 +76,9 @@ Diese Version enthält keine Havok-Unterstützung und wird nicht für das Hochladen von Physik in Second Life empfohlen. Unvorhersehbare Ergebnisse sind möglich! + + Eine oder mehrere Dimensionen sind kleiner als 0,5m - nur Hüllen-basierte (analysierte) physische Formen werden korrekt funktionieren. + Ein unbekannter Fehler ist aufgetreten. diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index 4c40e9417e..862b75daf8 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -4839,8 +4839,15 @@ Bitte kopieren Sie diese in Ihr Inventar und versuchen Sie es erneut. Test-Ergebnis für gip-Level 6 Datei-Komprimierung für [FILE] mit Größe [SIZE] KB: Packen: [PACK_TIME]s [PSIZE]KB Entpacken: [UNPACK_TIME]s [USIZE]KB - fail - + fail + + + [MESSAGE] +
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Drag to move, shift-drag to copy - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [DESC] [NUM] - - - Nothing selected. - - - - - [CAPACITY_STRING] [secondlife:///app/openfloater/object_weights More info] - - - - - - - Deed - - - Deed - - - You can modify this object - - - You can modify these objects - - - You can't modify this object - - - You can't modify these objects - - - You can't modify this object across a region boundary - - - You can't modify these objects across a region boundary - - - You must select entire object to set permissions - - - Price: L$ - - - Total Price: L$ - - - Price Per: L$ - - - Mixed Price - - - Mixed Sale - - - Multiple selection - - - Name: - - - - Description: - - - - Creator: - - - - secondlife:///app/agent/00000000-0000-0000-0000-000000000000/inspect TestString PleaseIgnore (please.ignore) - - - Owner: - - - - secondlife:///app/agent/00000000-0000-0000-0000-000000000000/inspect TestString PleaseIgnore (please.ignore) - - - Last Owner: - - - - secondlife:///app/agent/00000000-0000-0000-0000-000000000000/inspect TestString PleaseIgnore (please.ignore) - - - Group: - - - - secondlife:///app/agent/00000000-0000-0000-0000-000000000000/inspect Loading... - - - - - - You can modify this object - - - Anyone: - - - - - - Next owner: - - - - - - - B: - - - O: - - - G: - - - E: - - - N: - - - F: - - - - - Pathfinding attributes: - - - - - - - - - Paste Position -[VALUE] - - - Paste Size -[VALUE] - - - Paste Rotation -[VALUE] - - - - - - - Position (meters) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path Cut (begin/end) - - - - - Hollow - - - Skew - - - - - Hollow Shape - - - - - - - - - Twist (begin/end) - - - - - Taper - - - Hole Size - - - - - Top Shear - - - - - Profile Cut (begin/end) - - - Dimple (begin/end) - - - Slice (begin/end) - - - - - Taper Profile - - - - - Radius - - - Revolutions - - - - - - - - Stitching type - - - - - - - - - - Mesh Information: - - - - -High: -Medium: -Low: -Lowest: - - -[HIGHTRIS] -[MIDTRIS] -[LOWTRIS] -[LOWESTTRIS] - - - - - - - - - - - - - - - - - Linden Lab Second Life Viewer default ([FACTOR]) - - [APP_NAME] Viewer default ([FACTOR]) - - [APP_NAME_ABBR] - - [FACTOR] - - -High ↔ Med -Med ↔ Low -Low ↔ Lwst - - -[HIGH2MED] -[MED2LOW] -[LOW2LOWEST] - - - - - - This table shows the LOD change boundaries in metres from the camera. - - - - - None - Prim - Convex Hull - - Select only one primitive to edit features. - - - Edit object features: - - - - - - - - - - - - - - - - - - - - - - - Physics Shape Type: - - - - diff --git a/indra/newview/skins/starlight/xui/en/floater_ui_preview.xml b/indra/newview/skins/starlight/xui/en/floater_ui_preview.xml deleted file mode 100644 index df26a35f6f..0000000000 --- a/indra/newview/skins/starlight/xui/en/floater_ui_preview.xml +++ /dev/null @@ -1,420 +0,0 @@ - - - -Select an editor by setting the environment variable LL_XUI_EDITOR -or the ExternalEditor setting -or specifying its path in the "Editor Path" field. - - - Primary Language: - - - - - - - Me - - - - - Person - - - - - Infohub - - - - - Land Sale - - - - land auction - - - - by owner - - - - - Go Home - - - Events: - - - - - - General - - - - - - Moderate - - - - - - Adult - - - - - - - Find on Map - - - - - - - - - - - - - - - - - - - - - - - - - Location: - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlight/xui/en/main_view.xml b/indra/newview/skins/starlight/xui/en/main_view.xml deleted file mode 100644 index f0708bbfe1..0000000000 --- a/indra/newview/skins/starlight/xui/en/main_view.xml +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlight/xui/en/panel_avatar_tag.xml b/indra/newview/skins/starlight/xui/en/panel_avatar_tag.xml deleted file mode 100644 index fcdb705240..0000000000 --- a/indra/newview/skins/starlight/xui/en/panel_avatar_tag.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - Angela Tester - - - - - The quick brown fox jumps over the lazy dog. - - diff --git a/indra/newview/skins/starlight/xui/en/panel_classified_info.xml b/indra/newview/skins/starlight/xui/en/panel_classified_info.xml deleted file mode 100644 index b3f4af97a8..0000000000 --- a/indra/newview/skins/starlight/xui/en/panel_classified_info.xml +++ /dev/null @@ -1,470 +0,0 @@ - - - - Moderate - - - General Content - - - L$[PRICE] - - - [TELEPORT] teleport, [MAP] map, [PROFILE] profile - - - [mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt] - - - Enabled - - - Disabled - - - - - - - - -Warning: the home page specified in the General tab fails to pass this whitelist. It has been disabled until a valid entry has been added. - - - diff --git a/indra/newview/skins/starlight/xui/en/panel_my_profile.xml b/indra/newview/skins/starlight/xui/en/panel_my_profile.xml deleted file mode 100644 index bb8b7c3a35..0000000000 --- a/indra/newview/skins/starlight/xui/en/panel_my_profile.xml +++ /dev/null @@ -1,382 +0,0 @@ - - - -[ACCTTYPE] -[PAYMENTINFO] [FIRESTORM][FSDEV][FSSUPP][FSQA][FSGW] - - - - - - - - http://www.secondlife.com/account/billing.php?lang=en - - - http://www.secondlife.com/account/partners.php?lang=en - - - - - - [REG_DATE] ([AGE]) - - - [NAME] - - - [DISPLAY_NAME] - - - - - - - - - - - Resident. No payment info on file. - Linden. - - - - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean viverra orci et justo sagittis aliquet.Nullamma lesuada mauris sit amet ipsum. adipiscing elit. Ae nean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. - - - - - - - - - - - - - - - - - Nearby Media - - - Show: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlight/xui/en/panel_notes.xml b/indra/newview/skins/starlight/xui/en/panel_notes.xml deleted file mode 100644 index 7c0ac7e085..0000000000 --- a/indra/newview/skins/starlight/xui/en/panel_notes.xml +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The Mighty Moose of mooseville soundvillemoose - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlight/xui/en/panel_places.xml b/indra/newview/skins/starlight/xui/en/panel_places.xml deleted file mode 100644 index 12309c77de..0000000000 --- a/indra/newview/skins/starlight/xui/en/panel_places.xml +++ /dev/null @@ -1,420 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlight/xui/en/panel_status_bar.xml b/indra/newview/skins/starlight/xui/en/panel_status_bar.xml deleted file mode 100644 index ad7da6fde1..0000000000 --- a/indra/newview/skins/starlight/xui/en/panel_status_bar.xml +++ /dev/null @@ -1,423 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlight/xui/en/sidepanel_appearance.xml b/indra/newview/skins/starlight/xui/en/sidepanel_appearance.xml deleted file mode 100644 index 1f252a06b1..0000000000 --- a/indra/newview/skins/starlight/xui/en/sidepanel_appearance.xml +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/floater_price_for_listing.xml b/indra/newview/skins/starlightcui/xui/en/floater_price_for_listing.xml deleted file mode 100644 index 616bbdc47d..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/floater_price_for_listing.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - Your classified ad will run for one week from the day it is published. - -Your ad's position in the classified listings is determined by how much you choose to pay. - -The highest paid ads go to the top of the list, and appear higher in searches. - - - Price for Ad: - - - L$ - - - - - - - - - Drag to move, shift-drag to copy - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [DESC] [NUM] - - - Nothing selected. - - - - - [CAPACITY_STRING] [secondlife:///app/openfloater/object_weights More info] - - - - - - - Deed - - - Deed - - - You can modify this object - - - You can modify these objects - - - You can't modify this object - - - You can't modify these objects - - - You can't modify this object across a region boundary - - - You can't modify these objects across a region boundary - - - You must select entire object to set permissions - - - Price: L$ - - - Total Price: L$ - - - Price Per: L$ - - - Mixed Price - - - Mixed Sale - - - Multiple selection - - - Name: - - - - Description: - - - - Creator: - - - - secondlife:///app/agent/00000000-0000-0000-0000-000000000000/inspect TestString PleaseIgnore (please.ignore) - - - Owner: - - - - secondlife:///app/agent/00000000-0000-0000-0000-000000000000/inspect TestString PleaseIgnore (please.ignore) - - - Last Owner: - - - - secondlife:///app/agent/00000000-0000-0000-0000-000000000000/inspect TestString PleaseIgnore (please.ignore) - - - Group: - - - - secondlife:///app/agent/00000000-0000-0000-0000-000000000000/inspect Loading... - - - - - - You can modify this object - - - Anyone: - - - - - - Next owner: - - - - - - - B: - - - O: - - - G: - - - E: - - - N: - - - F: - - - - - Pathfinding attributes: - - - - - - - - - Paste Position -[VALUE] - - - Paste Size -[VALUE] - - - Paste Rotation -[VALUE] - - - - - - - Position (meters) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path Cut (begin/end) - - - - - Hollow - - - Skew - - - - - Hollow Shape - - - - - - - - - Twist (begin/end) - - - - - Taper - - - Hole Size - - - - - Top Shear - - - - - Profile Cut (begin/end) - - - Dimple (begin/end) - - - Slice (begin/end) - - - - - Taper Profile - - - - - Radius - - - Revolutions - - - - - - - - Stitching type - - - - - - - - - - Mesh Information: - - - - -High: -Medium: -Low: -Lowest: - - -[HIGHTRIS] -[MIDTRIS] -[LOWTRIS] -[LOWESTTRIS] - - - - - - - - - - - - - - - - - Linden Lab Second Life Viewer default ([FACTOR]) - - [APP_NAME] Viewer default ([FACTOR]) - - [APP_NAME_ABBR] - - [FACTOR] - - -High ↔ Med -Med ↔ Low -Low ↔ Lwst - - -[HIGH2MED] -[MED2LOW] -[LOW2LOWEST] - - - - - - This table shows the LOD change boundaries in metres from the camera. - - - - - None - Prim - Convex Hull - - Select only one primitive to edit features. - - - Edit object features: - - - - - - - - - - - - - - - - - - - - - - - Physics Shape Type: - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/floater_ui_preview.xml b/indra/newview/skins/starlightcui/xui/en/floater_ui_preview.xml deleted file mode 100644 index 65bde85d2a..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/floater_ui_preview.xml +++ /dev/null @@ -1,420 +0,0 @@ - - - -Select an editor by setting the environment variable LL_XUI_EDITOR -or the ExternalEditor setting -or specifying its path in the "Editor Path" field. - - - Primary Language: - - - - - - - Me - - - - - Person - - - - - Infohub - - - - - Land Sale - - - - land auction - - - - by owner - - - - - Go Home - - - Events: - - - - - - General - - - - - - Moderate - - - - - - Adult - - - - - - - Find on Map - - - - - - - - - - - - - - - - - - - - - - - - - Location: - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/line_editor.xml b/indra/newview/skins/starlightcui/xui/en/line_editor.xml deleted file mode 100644 index b6fd4bb15f..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/line_editor.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - diff --git a/indra/newview/skins/starlightcui/xui/en/main_view.xml b/indra/newview/skins/starlightcui/xui/en/main_view.xml deleted file mode 100644 index 8f2e284a7b..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/main_view.xml +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/panel_avatar_tag.xml b/indra/newview/skins/starlightcui/xui/en/panel_avatar_tag.xml deleted file mode 100644 index fcdb705240..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/panel_avatar_tag.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - Angela Tester - - - - - The quick brown fox jumps over the lazy dog. - - diff --git a/indra/newview/skins/starlightcui/xui/en/panel_classified_info.xml b/indra/newview/skins/starlightcui/xui/en/panel_classified_info.xml deleted file mode 100644 index b3f4af97a8..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/panel_classified_info.xml +++ /dev/null @@ -1,470 +0,0 @@ - - - - Moderate - - - General Content - - - L$[PRICE] - - - [TELEPORT] teleport, [MAP] map, [PROFILE] profile - - - [mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt] - - - Enabled - - - Disabled - - - - - - - - -Warning: the home page specified in the General tab fails to pass this whitelist. It has been disabled until a valid entry has been added. - - - diff --git a/indra/newview/skins/starlightcui/xui/en/panel_my_profile.xml b/indra/newview/skins/starlightcui/xui/en/panel_my_profile.xml deleted file mode 100644 index bb8b7c3a35..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/panel_my_profile.xml +++ /dev/null @@ -1,382 +0,0 @@ - - - -[ACCTTYPE] -[PAYMENTINFO] [FIRESTORM][FSDEV][FSSUPP][FSQA][FSGW] - - - - - - - - http://www.secondlife.com/account/billing.php?lang=en - - - http://www.secondlife.com/account/partners.php?lang=en - - - - - - [REG_DATE] ([AGE]) - - - [NAME] - - - [DISPLAY_NAME] - - - - - - - - - - - Resident. No payment info on file. - Linden. - - - - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean viverra orci et justo sagittis aliquet.Nullamma lesuada mauris sit amet ipsum. adipiscing elit. Ae nean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. - - - - - - - - - - - - - - - - - Nearby Media - - - Show: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/panel_notes.xml b/indra/newview/skins/starlightcui/xui/en/panel_notes.xml deleted file mode 100644 index 7c0ac7e085..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/panel_notes.xml +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The Mighty Moose of mooseville soundvillemoose - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/panel_places.xml b/indra/newview/skins/starlightcui/xui/en/panel_places.xml deleted file mode 100644 index 12309c77de..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/panel_places.xml +++ /dev/null @@ -1,420 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/panel_stand_stop_flying.xml b/indra/newview/skins/starlightcui/xui/en/panel_stand_stop_flying.xml deleted file mode 100644 index ee6b2b9d44..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/panel_stand_stop_flying.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/panel_status_bar.xml b/indra/newview/skins/starlightcui/xui/en/panel_status_bar.xml deleted file mode 100644 index e911fc9b6c..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/panel_status_bar.xml +++ /dev/null @@ -1,419 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/sidepanel_appearance.xml b/indra/newview/skins/starlightcui/xui/en/sidepanel_appearance.xml deleted file mode 100644 index 6a64942ed6..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/sidepanel_appearance.xml +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/chiclet_im_p2p.xml b/indra/newview/skins/starlightcui/xui/en/widgets/chiclet_im_p2p.xml deleted file mode 100644 index 37144bb81b..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/chiclet_im_p2p.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/clothing_list_item.xml b/indra/newview/skins/starlightcui/xui/en/widgets/clothing_list_item.xml deleted file mode 100644 index d83f44737e..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/clothing_list_item.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/combo_box.xml b/indra/newview/skins/starlightcui/xui/en/widgets/combo_box.xml deleted file mode 100644 index a2e735cb08..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/combo_box.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/deletable_wearable_list_item.xml b/indra/newview/skins/starlightcui/xui/en/widgets/deletable_wearable_list_item.xml deleted file mode 100644 index bd977aa4a6..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/deletable_wearable_list_item.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/drop_down.xml b/indra/newview/skins/starlightcui/xui/en/widgets/drop_down.xml deleted file mode 100644 index 5260e080cb..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/drop_down.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/dummy_clothing_list_item.xml b/indra/newview/skins/starlightcui/xui/en/widgets/dummy_clothing_list_item.xml deleted file mode 100644 index 11bc36c01d..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/dummy_clothing_list_item.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/floater.xml b/indra/newview/skins/starlightcui/xui/en/widgets/floater.xml deleted file mode 100644 index 3829e1f84a..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/floater.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/fs_chiclet_im_p2p.xml b/indra/newview/skins/starlightcui/xui/en/widgets/fs_chiclet_im_p2p.xml deleted file mode 100644 index 07d8962d72..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/fs_chiclet_im_p2p.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/gesture_combo_list.xml b/indra/newview/skins/starlightcui/xui/en/widgets/gesture_combo_list.xml deleted file mode 100644 index 872d12cb87..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/gesture_combo_list.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/icon.xml b/indra/newview/skins/starlightcui/xui/en/widgets/icon.xml deleted file mode 100644 index fe0cee9c59..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/icon.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/inventory_list_item.xml b/indra/newview/skins/starlightcui/xui/en/widgets/inventory_list_item.xml deleted file mode 100644 index f31b247822..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/inventory_list_item.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/inventory_panel.xml b/indra/newview/skins/starlightcui/xui/en/widgets/inventory_panel.xml deleted file mode 100644 index 8aea659372..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/inventory_panel.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/line_editor.xml b/indra/newview/skins/starlightcui/xui/en/widgets/line_editor.xml deleted file mode 100644 index b6fd4bb15f..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/line_editor.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/location_input.xml b/indra/newview/skins/starlightcui/xui/en/widgets/location_input.xml deleted file mode 100644 index 4e61843aa9..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/location_input.xml +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/menu.xml b/indra/newview/skins/starlightcui/xui/en/widgets/menu.xml deleted file mode 100644 index c074308134..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/menu.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/menu_bar.xml b/indra/newview/skins/starlightcui/xui/en/widgets/menu_bar.xml deleted file mode 100644 index 71a624ac04..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/menu_bar.xml +++ /dev/null @@ -1,8 +0,0 @@ - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/panel.xml b/indra/newview/skins/starlightcui/xui/en/widgets/panel.xml deleted file mode 100644 index 008d06a705..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/panel.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/progress_bar.xml b/indra/newview/skins/starlightcui/xui/en/widgets/progress_bar.xml deleted file mode 100644 index 2a6ea05b84..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/progress_bar.xml +++ /dev/null @@ -1,12 +0,0 @@ - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/recent_inventory_panel.xml b/indra/newview/skins/starlightcui/xui/en/widgets/recent_inventory_panel.xml deleted file mode 100644 index fe0d93a9c2..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/recent_inventory_panel.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/scroll_bar.xml b/indra/newview/skins/starlightcui/xui/en/widgets/scroll_bar.xml deleted file mode 100644 index 05b601eadd..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/scroll_bar.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/scroll_container.xml b/indra/newview/skins/starlightcui/xui/en/widgets/scroll_container.xml deleted file mode 100644 index abae7f7683..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/scroll_container.xml +++ /dev/null @@ -1,7 +0,0 @@ - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/simple_text_editor.xml b/indra/newview/skins/starlightcui/xui/en/widgets/simple_text_editor.xml deleted file mode 100644 index f9cf52c8fc..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/simple_text_editor.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/slider_bar.xml b/indra/newview/skins/starlightcui/xui/en/widgets/slider_bar.xml deleted file mode 100644 index 061cbfc177..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/slider_bar.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/split_button.xml b/indra/newview/skins/starlightcui/xui/en/widgets/split_button.xml deleted file mode 100644 index 78258bc3f0..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/split_button.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/tab_container.xml b/indra/newview/skins/starlightcui/xui/en/widgets/tab_container.xml deleted file mode 100644 index ed50e4f104..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/tab_container.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/talk_button.xml b/indra/newview/skins/starlightcui/xui/en/widgets/talk_button.xml deleted file mode 100644 index fd931a896b..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/talk_button.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - diff --git a/indra/newview/skins/starlightcui/xui/en/widgets/toolbar.xml b/indra/newview/skins/starlightcui/xui/en/widgets/toolbar.xml deleted file mode 100644 index 00d755cc1a..0000000000 --- a/indra/newview/skins/starlightcui/xui/en/widgets/toolbar.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - -