diff options
| author | Jonathan "Geenz" Goodman <geenz@geenzo.com> | 2026-08-11 21:39:19 -0400 |
|---|---|---|
| committer | Jonathan "Geenz" Goodman <geenz@geenzo.com> | 2026-08-11 21:39:19 -0400 |
| commit | 8cabc33e960ca93fdc1a32c77cf611269d95d51b (patch) | |
| tree | 931fcecac10bf73214efa07cc3d704ba2bd01272 /indra/llwindow | |
| parent | 9b7ab49575b54523128952af6686d17eb6696725 (diff) | |
| parent | d045f9aa32789a35628aced166145c182751acbf (diff) | |
Merge remote-tracking branch 'origin/develop-linux' into geenz/linux-to-develop
Diffstat (limited to 'indra/llwindow')
23 files changed, 2021 insertions, 2034 deletions
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 3dae2d1067..5f8a9a64eb 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -12,12 +12,14 @@ project(llwindow) include(00-Common) include(DragDrop) +include(Linking) include(LLCommon) include(LLImage) include(LLWindow) include(UI) include(ViewerMiscLibs) include(GLM) +include(SDL3) set(llwindow_SOURCE_FILES llcursortypes.cpp @@ -66,11 +68,13 @@ set(macosx_HEADER_FILES ) set(linux_SOURCE_FILES + llsdl.cpp llkeyboardsdl.cpp llwindowsdl.cpp ) set(linux_HEADER_FILES + llsdl.h llkeyboardsdl.h llwindowsdl.h ) @@ -99,28 +103,16 @@ set(llwindow_LINK_LIBRARIES ll::glm ll::glext ll::uilibraries - ll::SDL ) -# Libraries on which this library depends, needed for Linux builds -# Sort by high-level to low-level -if (LINUX) + +if (USE_SDL_WINDOW) list(APPEND viewer_SOURCE_FILES ${linux_SOURCE_FILES}) list(APPEND viewer_HEADER_FILES ${linux_HEADER_FILES}) - if (BUILD_HEADLESS) - set(llwindowheadless_LINK_LIBRARIES - ${LLCOMMON_LIBRARIES} - ${LLIMAGE_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLRENDER_HEADLESS_LIBRARIES} - ${LLFILESYSTEM_LIBRARIES} - ${LLWINDOW_HEADLESS_LIBRARIES} - ${LLXML_LIBRARIES} - fontconfig # For FCInit and other FC* functions. - ) - endif (BUILD_HEADLESS) - -endif (LINUX) + list(APPEND llwindow_LINK_LIBRARIES + ll::SDL3 + ) +endif () if (DARWIN) list(APPEND llwindow_SOURCE_FILES ${macosx_SOURCE_FILES}) @@ -133,6 +125,13 @@ if (DARWIN) PROPERTIES COMPILE_FLAGS "-fpascal-strings" ) + + set_source_files_properties( + llwindowmacosx-objc.mm + llopenglview-objc.mm + PROPERTIES + SKIP_PRECOMPILE_HEADERS TRUE + ) endif (DARWIN) @@ -147,32 +146,55 @@ if (WINDOWS) ) endif (WINDOWS) -if (SOLARIS) - list(APPEND llwindow_SOURCE_FILES - llwindowsolaris.cpp - ) - list(APPEND llwindow_HEADER_FILES - llwindowsolaris.h - ) -endif (SOLARIS) if (BUILD_HEADLESS) set(llwindowheadless_SOURCE_FILES - llwindowmesaheadless.cpp - llmousehandler.cpp - ) + llcursortypes.cpp + llkeyboard.cpp + llkeyboardheadless.cpp + llwindowheadless.cpp + llwindowcallbacks.cpp + llwindow.cpp + llwindowmesaheadless.cpp + llmousehandler.cpp + ) + set(llwindowheadless_HEADER_FILES - llwindowmesaheadless.h - llmousehandler.h - ) + llcursortypes.h + llkeyboard.h + llkeyboardheadless.h + llwindowheadless.h + llwindowcallbacks.h + llwindowmesaheadless.h + llmousehandler.h + ) + add_library (llwindowheadless - ${llwindow_SOURCE_FILES} ${llwindowheadless_SOURCE_FILES} + ${llwindowheadless_HEADER_FILES} ) - set_property(TARGET llwindowheadless - PROPERTY COMPILE_DEFINITIONS LL_MESA=1 LL_MESA_HEADLESS=1 - ) - target_link_libraries (llwindowheadless ${llwindowheadless_LINK_LIBRARIES} dl) + + target_compile_definitions( llwindowheadless PUBLIC LL_MESA_HEADLESS=1 ) + + target_link_libraries (llwindowheadless + llcommon + llimage + llmath + llrenderheadless + llfilesystem + llxml + ll::glm + ll::glext + ll::zlib-ng + PkgConfig::OSMESA + fontconfig + dl + ) + target_include_directories(llwindowheadless INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + + if (USE_PRECOMPILED_HEADERS) + target_precompile_headers(llwindowheadless REUSE_FROM llprecompiled) + endif () endif (BUILD_HEADLESS) if (llwindow_HEADER_FILES) @@ -224,14 +246,16 @@ elseif (LINUX) ) endif() -if (SDL_FOUND) - set_property(TARGET llwindow - PROPERTY COMPILE_DEFINITIONS LL_SDL=1 - ) -endif (SDL_FOUND) +target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES}) +target_include_directories(llwindow INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + +if (USE_SDL_WINDOW) + target_compile_definitions( llwindow PUBLIC LL_SDL_WINDOW=1 ) +endif() - target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES}) - target_include_directories(llwindow INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +if (USE_PRECOMPILED_HEADERS) + target_precompile_headers(llwindow REUSE_FROM llprecompiled) +endif () if (DARWIN) target_link_libraries(llwindow ${CARBON_LIBRARY}) diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index b642736d8e..df69b1390c 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -43,7 +43,6 @@ std::map<KEY,std::string> LLKeyboard::sKeysToNames; std::map<std::string,KEY> LLKeyboard::sNamesToKeys; LLKeyStringTranslatorFunc* LLKeyboard::mStringTranslator = NULL; // Used for l10n + PC/Mac/Linux accelerator labeling - // // Class Implementation // @@ -164,6 +163,7 @@ void LLKeyboard::resetKeyDownAndHandle() mCallbacks->handleTranslatedKeyUp(i, mask); } } + mCurTranslatedKey = KEY_NONE; } // BUG this has to be called when an OS dialog is shown, otherwise modifier key state @@ -197,12 +197,10 @@ void LLKeyboard::resetKeys() } -bool LLKeyboard::translateKey(const U16 os_key, KEY *out_key) +bool LLKeyboard::translateKey(const NATIVE_KEY_TYPE os_key, KEY *out_key) { - std::map<U16, KEY>::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; @@ -216,11 +214,9 @@ bool LLKeyboard::translateKey(const U16 os_key, KEY *out_key) } } - -U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) +LLKeyboard::NATIVE_KEY_TYPE LLKeyboard::inverseTranslateKey(const KEY translated_key) { - std::map<KEY, U16>::iterator iter; - iter = mInvTranslateKeyMap.find(translated_key); + auto iter = mInvTranslateKeyMap.find(translated_key); if (iter == mInvTranslateKeyMap.end()) { return 0; @@ -232,7 +228,7 @@ U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) } -bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask) +bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key, MASK translated_mask) { bool handled = false; bool repeated = false; @@ -260,7 +256,7 @@ bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask } -bool LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask) +bool LLKeyboard::handleTranslatedKeyUp(KEY translated_key, MASK translated_mask) { bool handled = false; if( mKeyLevel[translated_key] ) diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index 067445d24c..a092787cef 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -54,6 +54,13 @@ class LLWindowCallbacks; class LLKeyboard { public: +#ifdef LL_SDL_WINDOW + // linux relies on SDL which uses U32 for its native key type + typedef U32 NATIVE_KEY_TYPE; +#else + // on non-linux platforms we can get by with a smaller native key type + typedef U16 NATIVE_KEY_TYPE; +#endif LLKeyboard(); virtual ~LLKeyboard(); @@ -66,16 +73,15 @@ 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); - bool handleTranslatedKeyUp(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes - bool handleTranslatedKeyDown(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes - + bool translateKey(const NATIVE_KEY_TYPE os_key, KEY *translated_key); + NATIVE_KEY_TYPE inverseTranslateKey(const KEY translated_key); + bool handleTranslatedKeyUp(KEY translated_key, MASK translated_mask); // Translated into "Linden" keycodes + bool handleTranslatedKeyDown(KEY translated_key, MASK translated_mask); // Translated into "Linden" keycodes - 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; -#ifdef LL_DARWIN +#if LL_DARWIN && !LL_SDL_WINDOW // We only actually use this for macOS. virtual void handleModifier(MASK mask) = 0; #endif // LL_DARWIN @@ -110,8 +116,8 @@ protected: void addKeyName(KEY key, const std::string& name); protected: - std::map<U16, KEY> mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs - std::map<KEY, U16> mInvTranslateKeyMap; // Map of translations from Linden KEYs to OS keys + std::map<NATIVE_KEY_TYPE, KEY> mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs + std::map<KEY, NATIVE_KEY_TYPE> 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 8669a5b41a..50d03aaf20 100644 --- a/indra/llwindow/llkeyboardheadless.cpp +++ b/indra/llwindow/llkeyboardheadless.cpp @@ -31,21 +31,23 @@ LLKeyboardHeadless::LLKeyboardHeadless() { } -void LLKeyboardHeadless::resetMaskKeys() -{ } - - -bool LLKeyboardHeadless::handleKeyDown(const U16 key, const U32 mask) -{ return false; } +bool LLKeyboardHeadless::handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) +{ + return false; +} +bool LLKeyboardHeadless::handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) +{ + return false; +} -bool LLKeyboardHeadless::handleKeyUp(const U16 key, const U32 mask) -{ return false; } +void LLKeyboardHeadless::resetMaskKeys() +{ } MASK LLKeyboardHeadless::currentMask(bool for_mouse_event) { return MASK_NONE; } -#ifdef LL_DARWIN +#if LL_DARWIN && !LL_SDL_WINDOW void LLKeyboardHeadless::handleModifier(MASK mask) { @@ -65,6 +67,7 @@ void LLKeyboardHeadless::scanKeyboard() mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); } } + mCurScanKey = KEY_NONE; // Reset edges for next frame for (S32 key = 0; key < KEY_COUNT; key++) diff --git a/indra/llwindow/llkeyboardheadless.h b/indra/llwindow/llkeyboardheadless.h index 2528f0e3f1..364fb03fe7 100644 --- a/indra/llwindow/llkeyboardheadless.h +++ b/indra/llwindow/llkeyboardheadless.h @@ -33,15 +33,15 @@ class LLKeyboardHeadless : public LLKeyboard { public: LLKeyboardHeadless(); - /*virtual*/ ~LLKeyboardHeadless() {}; + ~LLKeyboardHeadless() = default; - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); -#ifdef LL_DARWIN - /*virtual*/ void handleModifier(MASK mask); + bool handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + bool handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + void resetMaskKeys() override; + MASK currentMask(bool for_mouse_event) override; + void scanKeyboard() override; +#if LL_DARWIN && !LL_SDL_WINDOW + void handleModifier(MASK mask) override; #endif }; diff --git a/indra/llwindow/llkeyboardmacosx.cpp b/indra/llwindow/llkeyboardmacosx.cpp index 89ff7c6d3f..1a403e5d94 100644 --- a/indra/llwindow/llkeyboardmacosx.cpp +++ b/indra/llwindow/llkeyboardmacosx.cpp @@ -162,7 +162,7 @@ LLKeyboardMacOSX::LLKeyboardMacOSX() void LLKeyboardMacOSX::resetMaskKeys() { - U32 mask = getModifiers(); + MASK mask = getModifiers(); // 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. @@ -187,7 +187,7 @@ void LLKeyboardMacOSX::resetMaskKeys() } /* -static bool translateKeyMac(const U16 key, const U32 mask, KEY &outKey, U32 &outMask) +static bool translateKeyMac(const U16 key, const MASK mask, KEY &outKey, U32 &outMask) { // Translate the virtual keycode into the keycodes the keyboard system expects. U16 virtualKey = (mask >> 24) & 0x0000007F; @@ -203,7 +203,7 @@ void LLKeyboardMacOSX::handleModifier(MASK mask) updateModifiers(mask); } -MASK LLKeyboardMacOSX::updateModifiers(const U32 mask) +MASK LLKeyboardMacOSX::updateModifiers(const MASK mask) { // translate the mask MASK out_mask = 0; @@ -226,7 +226,7 @@ MASK LLKeyboardMacOSX::updateModifiers(const U32 mask) return out_mask; } -bool LLKeyboardMacOSX::handleKeyDown(const U16 key, const U32 mask) +bool LLKeyboardMacOSX::handleKeyDown(const U16 key, MASK mask) { KEY translated_key = 0; U32 translated_mask = 0; @@ -243,7 +243,7 @@ bool LLKeyboardMacOSX::handleKeyDown(const U16 key, const U32 mask) } -bool LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask) +bool LLKeyboardMacOSX::handleKeyUp(const U16 key, MASK mask) { KEY translated_key = 0; U32 translated_mask = 0; @@ -262,7 +262,7 @@ bool LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask) MASK LLKeyboardMacOSX::currentMask(bool for_mouse_event) { MASK result = MASK_NONE; - U32 mask = getModifiers(); + MASK mask = getModifiers(); if (mask & MAC_SHIFT_KEY) result |= MASK_SHIFT; if (mask & MAC_CTRL_KEY) result |= MASK_CONTROL; @@ -291,6 +291,7 @@ void LLKeyboardMacOSX::scanKeyboard() mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); } } + mCurScanKey = KEY_NONE; // Reset edges for next frame for (key = 0; key < KEY_COUNT; key++) diff --git a/indra/llwindow/llkeyboardmacosx.h b/indra/llwindow/llkeyboardmacosx.h index 92ab5c9a85..c824e7b713 100644 --- a/indra/llwindow/llkeyboardmacosx.h +++ b/indra/llwindow/llkeyboardmacosx.h @@ -42,17 +42,17 @@ class LLKeyboardMacOSX : public LLKeyboard { public: LLKeyboardMacOSX(); - /*virtual*/ ~LLKeyboardMacOSX() {}; + ~LLKeyboardMacOSX() = default; - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); - /*virtual*/ void handleModifier(MASK mask); + bool handleKeyUp(const NATIVE_KEY_TYPE key, MASK mask) override; + bool handleKeyDown(const NATIVE_KEY_TYPE key, MASK mask) override; + void resetMaskKeys() override; + MASK currentMask(bool for_mouse_event) override; + void scanKeyboard() override; + void handleModifier(MASK mask) override; protected: - MASK updateModifiers(const U32 mask); + MASK updateModifiers(const MASK mask); void setModifierKeyLevel( KEY key, bool new_state ); bool translateNumpadKey( const U16 os_key, KEY *translated_key ); U16 inverseTranslateNumpadKey(const KEY translated_key); diff --git a/indra/llwindow/llkeyboardsdl.cpp b/indra/llwindow/llkeyboardsdl.cpp index 97198f0cc0..e4d096e2e9 100644 --- a/indra/llwindow/llkeyboardsdl.cpp +++ b/indra/llwindow/llkeyboardsdl.cpp @@ -24,12 +24,11 @@ * $/LicenseInfo$ */ -#if LL_SDL - #include "linden_common.h" #include "llkeyboardsdl.h" #include "llwindowcallbacks.h" -#include "SDL/SDL.h" + +#include "SDL3/SDL_keycode.h" LLKeyboardSDL::LLKeyboardSDL() { @@ -40,7 +39,7 @@ LLKeyboardSDL::LLKeyboardSDL() // Virtual key mappings from SDL_keysym.h ... // SDL maps the letter keys to the ASCII you'd expect, but it's lowercase... - U16 cur_char; + LLKeyboard::NATIVE_KEY_TYPE cur_char; for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) { mTranslateKeyMap[cur_char] = cur_char; @@ -74,7 +73,6 @@ LLKeyboardSDL::LLKeyboardSDL() mTranslateKeyMap[SDLK_RIGHT] = KEY_RIGHT; mTranslateKeyMap[SDLK_UP] = KEY_UP; mTranslateKeyMap[SDLK_DOWN] = KEY_DOWN; - mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; mTranslateKeyMap[SDLK_KP_ENTER] = KEY_RETURN; mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; mTranslateKeyMap[SDLK_BACKSPACE] = KEY_BACKSPACE; @@ -115,36 +113,35 @@ LLKeyboardSDL::LLKeyboardSDL() mTranslateKeyMap[SDLK_COMMA] = ','; mTranslateKeyMap[SDLK_MINUS] = '-'; mTranslateKeyMap[SDLK_PERIOD] = '.'; - mTranslateKeyMap[SDLK_BACKQUOTE] = '`'; + mTranslateKeyMap[SDLK_GRAVE] = '`'; mTranslateKeyMap[SDLK_SLASH] = KEY_DIVIDE; mTranslateKeyMap[SDLK_SEMICOLON] = ';'; mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; - mTranslateKeyMap[SDLK_QUOTE] = '\''; + mTranslateKeyMap[SDLK_APOSTROPHE] = '\''; // Build inverse map - std::map<U16, KEY>::iterator iter; - for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) + for (auto iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) { mInvTranslateKeyMap[iter->second] = iter->first; } // numpad map - mTranslateNumpadMap[SDLK_KP0] = KEY_PAD_INS; - mTranslateNumpadMap[SDLK_KP1] = KEY_PAD_END; - mTranslateNumpadMap[SDLK_KP2] = KEY_PAD_DOWN; - mTranslateNumpadMap[SDLK_KP3] = KEY_PAD_PGDN; - mTranslateNumpadMap[SDLK_KP4] = KEY_PAD_LEFT; - mTranslateNumpadMap[SDLK_KP5] = KEY_PAD_CENTER; - mTranslateNumpadMap[SDLK_KP6] = KEY_PAD_RIGHT; - mTranslateNumpadMap[SDLK_KP7] = KEY_PAD_HOME; - mTranslateNumpadMap[SDLK_KP8] = KEY_PAD_UP; - mTranslateNumpadMap[SDLK_KP9] = KEY_PAD_PGUP; + 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 (iter = mTranslateNumpadMap.begin(); + for (auto iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++) { @@ -154,45 +151,45 @@ LLKeyboardSDL::LLKeyboardSDL() void LLKeyboardSDL::resetMaskKeys() { - SDLMod mask = SDL_GetModState(); + 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) + if(mask & SDL_KMOD_SHIFT) { mKeyLevel[KEY_SHIFT] = true; } - if(mask & KMOD_CTRL) + if(mask & SDL_KMOD_CTRL) { mKeyLevel[KEY_CONTROL] = true; } - if(mask & KMOD_ALT) + if(mask & SDL_KMOD_ALT) { mKeyLevel[KEY_ALT] = true; } } -MASK LLKeyboardSDL::updateModifiers(const U32 mask) +MASK LLKeyboardSDL::updateModifiers(const MASK mask) { // translate the mask MASK out_mask = MASK_NONE; - if(mask & KMOD_SHIFT) + if(mask & SDL_KMOD_SHIFT) { out_mask |= MASK_SHIFT; } - if(mask & KMOD_CTRL) + if(mask & SDL_KMOD_CTRL) { out_mask |= MASK_CONTROL; } - if(mask & KMOD_ALT) + if(mask & SDL_KMOD_ALT) { out_mask |= MASK_ALT; } @@ -201,37 +198,37 @@ MASK LLKeyboardSDL::updateModifiers(const U32 mask) } -static U16 adjustNativekeyFromUnhandledMask(const U16 key, const U32 mask) +LLKeyboard::NATIVE_KEY_TYPE adjustNativekeyFromUnhandledMask(const LLKeyboard::NATIVE_KEY_TYPE key, const MASK mask) { // SDL doesn't automatically adjust the keysym according to // whether NUMLOCK is engaged, so we massage the keysym manually. - U16 rtn = key; - if (!(mask & KMOD_NUM)) + LLKeyboard::NATIVE_KEY_TYPE rtn = key; + if (!(mask & SDL_KMOD_NUM)) { switch (key) { - case SDLK_KP_PERIOD: rtn = SDLK_DELETE; break; - case SDLK_KP0: rtn = SDLK_INSERT; break; - case SDLK_KP1: rtn = SDLK_END; break; - case SDLK_KP2: rtn = SDLK_DOWN; break; - case SDLK_KP3: rtn = SDLK_PAGEDOWN; break; - case SDLK_KP4: rtn = SDLK_LEFT; break; - case SDLK_KP6: rtn = SDLK_RIGHT; break; - case SDLK_KP7: rtn = SDLK_HOME; break; - case SDLK_KP8: rtn = SDLK_UP; break; - case SDLK_KP9: rtn = SDLK_PAGEUP; break; + 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 U16 key, const U32 mask) +bool LLKeyboardSDL::handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, const MASK mask) { - U16 adjusted_nativekey; + LLKeyboard::NATIVE_KEY_TYPE adjusted_nativekey; KEY translated_key = 0; - U32 translated_mask = MASK_NONE; - bool handled = false; + MASK translated_mask = MASK_NONE; + bool handled = false; adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); @@ -246,12 +243,12 @@ bool LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask) } -bool LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) +bool LLKeyboardSDL::handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, const MASK mask) { - U16 adjusted_nativekey; + LLKeyboard::NATIVE_KEY_TYPE adjusted_nativekey; KEY translated_key = 0; U32 translated_mask = MASK_NONE; - bool handled = false; + bool handled = false; adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); @@ -268,16 +265,20 @@ bool LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) MASK LLKeyboardSDL::currentMask(bool for_mouse_event) { MASK result = MASK_NONE; - SDLMod mask = SDL_GetModState(); + 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; + if (mask & SDL_KMOD_SHIFT) + result |= MASK_SHIFT; + if (mask & SDL_KMOD_CTRL) + result |= MASK_CONTROL; + if (mask & SDL_KMOD_ALT) + result |= MASK_ALT; // For keyboard events, consider Meta keys equivalent to Control if (!for_mouse_event) { - if (mask & KMOD_META) result |= MASK_CONTROL; + if (mask & SDL_KMOD_GUI) + result |= MASK_CONTROL; } return result; @@ -296,6 +297,7 @@ void LLKeyboardSDL::scanKeyboard() mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); } } + mCurScanKey = KEY_NONE; // Reset edges for next frame for (S32 key = 0; key < KEY_COUNT; key++) @@ -310,15 +312,347 @@ void LLKeyboardSDL::scanKeyboard() } -bool LLKeyboardSDL::translateNumpadKey( const U16 os_key, KEY *translated_key) +bool LLKeyboardSDL::translateNumpadKey( const LLKeyboard::NATIVE_KEY_TYPE os_key, KEY *translated_key) { return translateKey(os_key, translated_key); } -U16 LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key) +LLKeyboard::NATIVE_KEY_TYPE LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key) { return inverseTranslateKey(translated_key); } -#endif +enum class WindowsVK : U32 +{ + LL_VK_UNKNOWN = 0, + LL_VK_CANCEL = 0x03, + LL_VK_BACK = 0x08, + LL_VK_TAB = 0x09, + LL_VK_CLEAR = 0x0C, + LL_VK_RETURN = 0x0D, + LL_VK_SHIFT = 0x10, + LL_VK_CONTROL = 0x11, + LL_VK_MENU = 0x12, + LL_VK_PAUSE = 0x13, + LL_VK_CAPITAL = 0x14, + LL_VK_KANA = 0x15, + LL_VK_HANGUL = 0x15, + LL_VK_JUNJA = 0x17, + LL_VK_FINAL = 0x18, + LL_VK_HANJA = 0x19, + LL_VK_KANJI = 0x19, + LL_VK_ESCAPE = 0x1B, + LL_VK_CONVERT = 0x1C, + LL_VK_NONCONVERT = 0x1D, + LL_VK_ACCEPT = 0x1E, + LL_VK_MODECHANGE = 0x1F, + LL_VK_SPACE = 0x20, + LL_VK_PRIOR = 0x21, + LL_VK_NEXT = 0x22, + LL_VK_END = 0x23, + LL_VK_HOME = 0x24, + LL_VK_LEFT = 0x25, + LL_VK_UP = 0x26, + LL_VK_RIGHT = 0x27, + LL_VK_DOWN = 0x28, + LL_VK_SELECT = 0x29, + LL_VK_PRINT = 0x2A, + LL_VK_EXECUTE = 0x2B, + LL_VK_SNAPSHOT = 0x2C, + LL_VK_INSERT = 0x2D, + LL_VK_DELETE = 0x2E, + LL_VK_HELP = 0x2F, + LL_VK_0 = 0x30, + LL_VK_1 = 0x31, + LL_VK_2 = 0x32, + LL_VK_3 = 0x33, + LL_VK_4 = 0x34, + LL_VK_5 = 0x35, + LL_VK_6 = 0x36, + LL_VK_7 = 0x37, + LL_VK_8 = 0x38, + LL_VK_9 = 0x39, + LL_VK_A = 0x41, + LL_VK_B = 0x42, + LL_VK_C = 0x43, + LL_VK_D = 0x44, + LL_VK_E = 0x45, + LL_VK_F = 0x46, + LL_VK_G = 0x47, + LL_VK_H = 0x48, + LL_VK_I = 0x49, + LL_VK_J = 0x4A, + LL_VK_K = 0x4B, + LL_VK_L = 0x4C, + LL_VK_M = 0x4D, + LL_VK_N = 0x4E, + LL_VK_O = 0x4F, + LL_VK_P = 0x50, + LL_VK_Q = 0x51, + LL_VK_R = 0x52, + LL_VK_S = 0x53, + LL_VK_T = 0x54, + LL_VK_U = 0x55, + LL_VK_V = 0x56, + LL_VK_W = 0x57, + LL_VK_X = 0x58, + LL_VK_Y = 0x59, + LL_VK_Z = 0x5A, + LL_VK_LWIN = 0x5B, + LL_VK_RWIN = 0x5C, + LL_VK_APPS = 0x5D, + LL_VK_SLEEP = 0x5F, + LL_VK_NUMPAD0 = 0x60, + LL_VK_NUMPAD1 = 0x61, + LL_VK_NUMPAD2 = 0x62, + LL_VK_NUMPAD3 = 0x63, + LL_VK_NUMPAD4 = 0x64, + LL_VK_NUMPAD5 = 0x65, + LL_VK_NUMPAD6 = 0x66, + LL_VK_NUMPAD7 = 0x67, + LL_VK_NUMPAD8 = 0x68, + LL_VK_NUMPAD9 = 0x69, + LL_VK_MULTIPLY = 0x6A, + LL_VK_ADD = 0x6B, + LL_VK_SEPARATOR = 0x6C, + LL_VK_SUBTRACT = 0x6D, + LL_VK_DECIMAL = 0x6E, + LL_VK_DIVIDE = 0x6F, + LL_VK_F1 = 0x70, + LL_VK_F2 = 0x71, + LL_VK_F3 = 0x72, + LL_VK_F4 = 0x73, + LL_VK_F5 = 0x74, + LL_VK_F6 = 0x75, + LL_VK_F7 = 0x76, + LL_VK_F8 = 0x77, + LL_VK_F9 = 0x78, + LL_VK_F10 = 0x79, + LL_VK_F11 = 0x7A, + LL_VK_F12 = 0x7B, + LL_VK_F13 = 0x7C, + LL_VK_F14 = 0x7D, + LL_VK_F15 = 0x7E, + LL_VK_F16 = 0x7F, + LL_VK_F17 = 0x80, + LL_VK_F18 = 0x81, + LL_VK_F19 = 0x82, + LL_VK_F20 = 0x83, + LL_VK_F21 = 0x84, + LL_VK_F22 = 0x85, + LL_VK_F23 = 0x86, + LL_VK_F24 = 0x87, + LL_VK_NUMLOCK = 0x90, + LL_VK_SCROLL = 0x91, + LL_VK_LSHIFT = 0xA0, + LL_VK_RSHIFT = 0xA1, + LL_VK_LCONTROL = 0xA2, + LL_VK_RCONTROL = 0xA3, + LL_VK_LMENU = 0xA4, + LL_VK_RMENU = 0xA5, + LL_VK_BROWSER_BACK = 0xA6, + LL_VK_BROWSER_FORWARD = 0xA7, + LL_VK_BROWSER_REFRESH = 0xA8, + LL_VK_BROWSER_STOP = 0xA9, + LL_VK_BROWSER_SEARCH = 0xAA, + LL_VK_BROWSER_FAVORITES = 0xAB, + LL_VK_BROWSER_HOME = 0xAC, + LL_VK_VOLUME_MUTE = 0xAD, + LL_VK_VOLUME_DOWN = 0xAE, + LL_VK_VOLUME_UP = 0xAF, + LL_VK_MEDIA_NEXT_TRACK = 0xB0, + LL_VK_MEDIA_PREV_TRACK = 0xB1, + LL_VK_MEDIA_STOP = 0xB2, + LL_VK_MEDIA_PLAY_PAUSE = 0xB3, + LL_VK_MEDIA_LAUNCH_MAIL = 0xB4, + LL_VK_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5, + LL_VK_MEDIA_LAUNCH_APP1 = 0xB6, + LL_VK_MEDIA_LAUNCH_APP2 = 0xB7, + LL_VK_OEM_1 = 0xBA, + LL_VK_OEM_PLUS = 0xBB, + LL_VK_OEM_COMMA = 0xBC, + LL_VK_OEM_MINUS = 0xBD, + LL_VK_OEM_PERIOD = 0xBE, + LL_VK_OEM_2 = 0xBF, + LL_VK_OEM_3 = 0xC0, + LL_VK_OEM_4 = 0xDB, + LL_VK_OEM_5 = 0xDC, + LL_VK_OEM_6 = 0xDD, + LL_VK_OEM_7 = 0xDE, + LL_VK_OEM_8 = 0xDF, + LL_VK_OEM_102 = 0xE2, + LL_VK_PROCESSKEY = 0xE5, + LL_VK_PACKET = 0xE7, + LL_VK_ATTN = 0xF6, + LL_VK_CRSEL = 0xF7, + LL_VK_EXSEL = 0xF8, + LL_VK_EREOF = 0xF9, + LL_VK_PLAY = 0xFA, + LL_VK_ZOOM = 0xFB, + LL_VK_NONAME = 0xFC, + LL_VK_PA1 = 0xFD, + LL_VK_OEM_CLEAR = 0xFE, +}; + +std::map< U32, U32 > mSDL_to_Win; + +U32 LLKeyboardSDL::mapSDLtoWin( U32 aSymbol ) +{ + // <FS:ND> Map SDLK_ virtual keys to Windows LL_VK_ virtual keys. + // Text is handled via unicode input (SDL_TEXTINPUT event) and does not need to be translated into LL_VK_ values as those match already. + if( mSDL_to_Win.empty() ) + { + + mSDL_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::LL_VK_BACK; + mSDL_to_Win[ SDLK_TAB ] = (U32)WindowsVK::LL_VK_TAB; + mSDL_to_Win[ 12 ] = (U32)WindowsVK::LL_VK_CLEAR; + mSDL_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::LL_VK_RETURN; + mSDL_to_Win[ 19 ] = (U32)WindowsVK::LL_VK_PAUSE; + mSDL_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::LL_VK_ESCAPE; + mSDL_to_Win[ SDLK_SPACE ] = (U32)WindowsVK::LL_VK_SPACE; + mSDL_to_Win[ SDLK_APOSTROPHE ] = (U32)WindowsVK::LL_VK_OEM_7; + mSDL_to_Win[ SDLK_COMMA ] = (U32)WindowsVK::LL_VK_OEM_COMMA; + mSDL_to_Win[ SDLK_MINUS ] = (U32)WindowsVK::LL_VK_OEM_MINUS; + mSDL_to_Win[ SDLK_PERIOD ] = (U32)WindowsVK::LL_VK_OEM_PERIOD; + mSDL_to_Win[ SDLK_SLASH ] = (U32)WindowsVK::LL_VK_OEM_2; + + mSDL_to_Win[ SDLK_0 ] = (U32)WindowsVK::LL_VK_0; + mSDL_to_Win[ SDLK_1 ] = (U32)WindowsVK::LL_VK_1; + mSDL_to_Win[ SDLK_2 ] = (U32)WindowsVK::LL_VK_2; + mSDL_to_Win[ SDLK_3 ] = (U32)WindowsVK::LL_VK_3; + mSDL_to_Win[ SDLK_4 ] = (U32)WindowsVK::LL_VK_4; + mSDL_to_Win[ SDLK_5 ] = (U32)WindowsVK::LL_VK_5; + mSDL_to_Win[ SDLK_6 ] = (U32)WindowsVK::LL_VK_6; + mSDL_to_Win[ SDLK_7 ] = (U32)WindowsVK::LL_VK_7; + mSDL_to_Win[ SDLK_8 ] = (U32)WindowsVK::LL_VK_8; + mSDL_to_Win[ SDLK_9 ] = (U32)WindowsVK::LL_VK_9; + + mSDL_to_Win[ SDLK_SEMICOLON ] = (U32)WindowsVK::LL_VK_OEM_1; + mSDL_to_Win[ SDLK_LESS ] = (U32)WindowsVK::LL_VK_OEM_102; + mSDL_to_Win[ SDLK_EQUALS ] = (U32)WindowsVK::LL_VK_OEM_PLUS; + mSDL_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::LL_VK_OEM_PLUS; + + mSDL_to_Win[ SDLK_LEFTBRACKET ] = (U32)WindowsVK::LL_VK_OEM_4; + mSDL_to_Win[ SDLK_BACKSLASH ] = (U32)WindowsVK::LL_VK_OEM_5; + mSDL_to_Win[ SDLK_RIGHTBRACKET ] = (U32)WindowsVK::LL_VK_OEM_6; + mSDL_to_Win[ SDLK_GRAVE ] = (U32)WindowsVK::LL_VK_OEM_8; + + mSDL_to_Win[ SDLK_A ] = (U32)WindowsVK::LL_VK_A; + mSDL_to_Win[ SDLK_B ] = (U32)WindowsVK::LL_VK_B; + mSDL_to_Win[ SDLK_C ] = (U32)WindowsVK::LL_VK_C; + mSDL_to_Win[ SDLK_D ] = (U32)WindowsVK::LL_VK_D; + mSDL_to_Win[ SDLK_E ] = (U32)WindowsVK::LL_VK_E; + mSDL_to_Win[ SDLK_F ] = (U32)WindowsVK::LL_VK_F; + mSDL_to_Win[ SDLK_G ] = (U32)WindowsVK::LL_VK_G; + mSDL_to_Win[ SDLK_H ] = (U32)WindowsVK::LL_VK_H; + mSDL_to_Win[ SDLK_I ] = (U32)WindowsVK::LL_VK_I; + mSDL_to_Win[ SDLK_J ] = (U32)WindowsVK::LL_VK_J; + mSDL_to_Win[ SDLK_K ] = (U32)WindowsVK::LL_VK_K; + mSDL_to_Win[ SDLK_L ] = (U32)WindowsVK::LL_VK_L; + mSDL_to_Win[ SDLK_M ] = (U32)WindowsVK::LL_VK_M; + mSDL_to_Win[ SDLK_N ] = (U32)WindowsVK::LL_VK_N; + mSDL_to_Win[ SDLK_O ] = (U32)WindowsVK::LL_VK_O; + mSDL_to_Win[ SDLK_P ] = (U32)WindowsVK::LL_VK_P; + mSDL_to_Win[ SDLK_Q ] = (U32)WindowsVK::LL_VK_Q; + mSDL_to_Win[ SDLK_R ] = (U32)WindowsVK::LL_VK_R; + mSDL_to_Win[ SDLK_S ] = (U32)WindowsVK::LL_VK_S; + mSDL_to_Win[ SDLK_T ] = (U32)WindowsVK::LL_VK_T; + mSDL_to_Win[ SDLK_Y ] = (U32)WindowsVK::LL_VK_U; + mSDL_to_Win[ SDLK_V ] = (U32)WindowsVK::LL_VK_V; + mSDL_to_Win[ SDLK_W ] = (U32)WindowsVK::LL_VK_W; + mSDL_to_Win[ SDLK_X ] = (U32)WindowsVK::LL_VK_X; + mSDL_to_Win[ SDLK_Y ] = (U32)WindowsVK::LL_VK_Y; + mSDL_to_Win[ SDLK_Z ] = (U32)WindowsVK::LL_VK_Z; + mSDL_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::LL_VK_DELETE; + + + mSDL_to_Win[ SDLK_NUMLOCKCLEAR ] = (U32)WindowsVK::LL_VK_NUMLOCK; + mSDL_to_Win[ SDLK_SCROLLLOCK ] = (U32)WindowsVK::LL_VK_SCROLL; + + mSDL_to_Win[ SDLK_HELP ] = (U32)WindowsVK::LL_VK_HELP; + mSDL_to_Win[ SDLK_PRINTSCREEN ] = (U32)WindowsVK::LL_VK_SNAPSHOT; + mSDL_to_Win[ SDLK_CANCEL ] = (U32)WindowsVK::LL_VK_CANCEL; + mSDL_to_Win[ SDLK_APPLICATION ] = (U32)WindowsVK::LL_VK_APPS; + + mSDL_to_Win[ SDLK_UNKNOWN ] = (U32)WindowsVK::LL_VK_UNKNOWN; + mSDL_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::LL_VK_BACK; + mSDL_to_Win[ SDLK_TAB ] = (U32)WindowsVK::LL_VK_TAB; + mSDL_to_Win[ SDLK_CLEAR ] = (U32)WindowsVK::LL_VK_CLEAR; + mSDL_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::LL_VK_RETURN; + mSDL_to_Win[ SDLK_PAUSE ] = (U32)WindowsVK::LL_VK_PAUSE; + mSDL_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::LL_VK_ESCAPE; + mSDL_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::LL_VK_DELETE; + + mSDL_to_Win[ SDLK_KP_PERIOD ] = (U32)WindowsVK::LL_VK_DELETE; // LL_VK_DECIMAL? + mSDL_to_Win[ SDLK_KP_DIVIDE ] = (U32)WindowsVK::LL_VK_DIVIDE; + mSDL_to_Win[ SDLK_KP_MULTIPLY] = (U32)WindowsVK::LL_VK_MULTIPLY; + mSDL_to_Win[ SDLK_KP_MINUS ] = (U32)WindowsVK::LL_VK_OEM_MINUS; // LL_VK_SUBSTRACT? + mSDL_to_Win[ SDLK_KP_PLUS ] = (U32)WindowsVK::LL_VK_OEM_PLUS; // LL_VK_ADD? + mSDL_to_Win[ SDLK_KP_ENTER ] = (U32)WindowsVK::LL_VK_RETURN; + mSDL_to_Win[ SDLK_KP_0 ] = (U32)WindowsVK::LL_VK_INSERT; + mSDL_to_Win[ SDLK_KP_1 ] = (U32)WindowsVK::LL_VK_END; + mSDL_to_Win[ SDLK_KP_2 ] = (U32)WindowsVK::LL_VK_DOWN; + mSDL_to_Win[ SDLK_KP_3 ] = (U32)WindowsVK::LL_VK_NEXT; + mSDL_to_Win[ SDLK_KP_4 ] = (U32)WindowsVK::LL_VK_LEFT; + mSDL_to_Win[ SDLK_KP_5 ] = (U32)WindowsVK::LL_VK_NUMPAD5; + mSDL_to_Win[ SDLK_KP_6 ] = (U32)WindowsVK::LL_VK_RIGHT; + mSDL_to_Win[ SDLK_KP_7 ] = (U32)WindowsVK::LL_VK_HOME; + mSDL_to_Win[ SDLK_KP_8 ] = (U32)WindowsVK::LL_VK_UP; + mSDL_to_Win[ SDLK_KP_9 ] = (U32)WindowsVK::LL_VK_PRIOR; + + // ? + + mSDL_to_Win[ SDLK_UP ] = (U32)WindowsVK::LL_VK_UP; + mSDL_to_Win[ SDLK_DOWN ] = (U32)WindowsVK::LL_VK_DOWN; + mSDL_to_Win[ SDLK_RIGHT ] = (U32)WindowsVK::LL_VK_RIGHT; + mSDL_to_Win[ SDLK_LEFT ] = (U32)WindowsVK::LL_VK_LEFT; + mSDL_to_Win[ SDLK_INSERT ] = (U32)WindowsVK::LL_VK_INSERT; + mSDL_to_Win[ SDLK_HOME ] = (U32)WindowsVK::LL_VK_HOME; + mSDL_to_Win[ SDLK_END ] = (U32)WindowsVK::LL_VK_END; + mSDL_to_Win[ SDLK_PAGEUP ] = (U32)WindowsVK::LL_VK_PRIOR; + mSDL_to_Win[ SDLK_PAGEDOWN ] = (U32)WindowsVK::LL_VK_NEXT; + mSDL_to_Win[ SDLK_F1 ] = (U32)WindowsVK::LL_VK_F1; + mSDL_to_Win[ SDLK_F2 ] = (U32)WindowsVK::LL_VK_F2; + mSDL_to_Win[ SDLK_F3 ] = (U32)WindowsVK::LL_VK_F3; + mSDL_to_Win[ SDLK_F4 ] = (U32)WindowsVK::LL_VK_F4; + mSDL_to_Win[ SDLK_F5 ] = (U32)WindowsVK::LL_VK_F5; + mSDL_to_Win[ SDLK_F6 ] = (U32)WindowsVK::LL_VK_F6; + mSDL_to_Win[ SDLK_F7 ] = (U32)WindowsVK::LL_VK_F7; + mSDL_to_Win[ SDLK_F8 ] = (U32)WindowsVK::LL_VK_F8; + mSDL_to_Win[ SDLK_F9 ] = (U32)WindowsVK::LL_VK_F9; + mSDL_to_Win[ SDLK_F10 ] = (U32)WindowsVK::LL_VK_F10; + mSDL_to_Win[ SDLK_F11 ] = (U32)WindowsVK::LL_VK_F11; + mSDL_to_Win[ SDLK_F12 ] = (U32)WindowsVK::LL_VK_F12; + mSDL_to_Win[ SDLK_F13 ] = (U32)WindowsVK::LL_VK_F13; + mSDL_to_Win[ SDLK_F14 ] = (U32)WindowsVK::LL_VK_F14; + mSDL_to_Win[ SDLK_F15 ] = (U32)WindowsVK::LL_VK_F15; + mSDL_to_Win[ SDLK_CAPSLOCK ] = (U32)WindowsVK::LL_VK_CAPITAL; + mSDL_to_Win[ SDLK_RSHIFT ] = (U32)WindowsVK::LL_VK_SHIFT; + mSDL_to_Win[ SDLK_LSHIFT ] = (U32)WindowsVK::LL_VK_SHIFT; + mSDL_to_Win[ SDLK_RCTRL ] = (U32)WindowsVK::LL_VK_CONTROL; + mSDL_to_Win[ SDLK_LCTRL ] = (U32)WindowsVK::LL_VK_CONTROL; + mSDL_to_Win[ SDLK_RALT ] = (U32)WindowsVK::LL_VK_MENU; + mSDL_to_Win[ SDLK_LALT ] = (U32)WindowsVK::LL_VK_MENU; + + mSDL_to_Win[ SDLK_MENU ] = (U32)WindowsVK::LL_VK_MENU; + + // LL_VK_MODECHANGE ? + // mSDL_to_Win[ SDLK_MODE ] = (U32)WindowsVK::LL_VK_MODE; + + // ? + // mSDL_to_Win[ SDLK_SYSREQ ] = (U32)WindowsVK::LL_VK_SYSREQ; + // mSDL_to_Win[ SDLK_POWER ] = (U32)WindowsVK::LL_VK_POWER; + // mSDL_to_Win[ SDLK_UNDO ] = (U32)WindowsVK::LL_VK_UNDO; + // mSDL_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::LL_VK_EQUALS; + // mSDL_to_Win[ 311 ] = (U32)WindowsVK::LL_VK_LWIN; + // mSDL_to_Win[ 312 ] = (U32)WindowsVK::LL_VK_RWIN; + // mSDL_to_Win[ SDLK_COLON ] = ? + } + + auto itr = mSDL_to_Win.find( aSymbol ); + if( itr != mSDL_to_Win.end() ) + return itr->second; + + return aSymbol; +} diff --git a/indra/llwindow/llkeyboardsdl.h b/indra/llwindow/llkeyboardsdl.h index fd348b28f2..2ebe647561 100644 --- a/indra/llwindow/llkeyboardsdl.h +++ b/indra/llwindow/llkeyboardsdl.h @@ -28,28 +28,31 @@ #define LL_LLKEYBOARDSDL_H #include "llkeyboard.h" -#include "SDL/SDL.h" +#include "SDL3/SDL.h" class LLKeyboardSDL : public LLKeyboard { public: LLKeyboardSDL(); - /*virtual*/ ~LLKeyboardSDL() {}; + ~LLKeyboardSDL() = default; - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); + bool handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + bool handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + void resetMaskKeys() override; + MASK currentMask(bool for_mouse_event) override; + void scanKeyboard() override; protected: - MASK updateModifiers(const U32 mask); + MASK updateModifiers(const MASK mask); void setModifierKeyLevel( KEY key, bool new_state ); - bool translateNumpadKey( const U16 os_key, KEY *translated_key ); - U16 inverseTranslateNumpadKey(const KEY translated_key); + bool translateNumpadKey( const LLKeyboard::NATIVE_KEY_TYPE os_key, KEY *translated_key ); + LLKeyboard::NATIVE_KEY_TYPE inverseTranslateNumpadKey(const KEY translated_key); private: - std::map<U16, KEY> mTranslateNumpadMap; // special map for translating OS keys to numpad keys - std::map<KEY, U16> mInvTranslateNumpadMap; // inverse of the above + std::map<LLKeyboard::NATIVE_KEY_TYPE, KEY> mTranslateNumpadMap; // special map for translating OS keys to numpad keys + std::map<KEY, LLKeyboard::NATIVE_KEY_TYPE> mInvTranslateNumpadMap; // inverse of the above + +public: + static U32 mapSDLtoWin( U32 ); }; #endif diff --git a/indra/llwindow/llkeyboardwin32.cpp b/indra/llwindow/llkeyboardwin32.cpp index 8d6b8d9b93..4ef0b493a5 100644 --- a/indra/llwindow/llkeyboardwin32.cpp +++ b/indra/llwindow/llkeyboardwin32.cpp @@ -197,7 +197,7 @@ MASK LLKeyboardWin32::updateModifiers() // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags -bool LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask) +bool LLKeyboardWin32::handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) { KEY translated_key; U32 translated_mask; @@ -214,7 +214,7 @@ bool LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask) } // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags -bool LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask) +bool LLKeyboardWin32::handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) { KEY translated_key; U32 translated_mask; diff --git a/indra/llwindow/llkeyboardwin32.h b/indra/llwindow/llkeyboardwin32.h index d0dfc5cfdd..fa223a2904 100644 --- a/indra/llwindow/llkeyboardwin32.h +++ b/indra/llwindow/llkeyboardwin32.h @@ -37,15 +37,16 @@ class LLKeyboardWin32 : public LLKeyboard { public: LLKeyboardWin32(); - /*virtual*/ ~LLKeyboardWin32() {}; + ~LLKeyboardWin32() = default; - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); - bool translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key); - U16 inverseTranslateExtendedKey(const KEY translated_key); + bool handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + bool handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, MASK mask) override; + void resetMaskKeys() override; + MASK currentMask(bool for_mouse_event) override; + void scanKeyboard() override; + + bool translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key); + U16 inverseTranslateExtendedKey(const KEY translated_key); protected: MASK updateModifiers(); diff --git a/indra/llwindow/llmousehandler.cpp b/indra/llwindow/llmousehandler.cpp index eeceab502a..959dde70b4 100644 --- a/indra/llwindow/llmousehandler.cpp +++ b/indra/llwindow/llmousehandler.cpp @@ -24,6 +24,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llmousehandler.h" //virtual diff --git a/indra/llwindow/llsdl.cpp b/indra/llwindow/llsdl.cpp new file mode 100644 index 0000000000..bc38120386 --- /dev/null +++ b/indra/llwindow/llsdl.cpp @@ -0,0 +1,149 @@ +/** + * @file llsdl.cpp + * @brief SDL initialization + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include <initializer_list> +#include <list> + +#include "SDL3/SDL.h" + +#ifndef LL_SDL_APP +#define SDL_MAIN_HANDLED 1 +#include "SDL3/SDL_main.h" +#endif + +#include "llerror.h" +#include "llwindow.h" + +bool gSDLMainHandled = false; + +void sdl_logger(void *userdata, int category, SDL_LogPriority priority, const char *message) +{ + switch (priority) + { + case SDL_LOG_PRIORITY_TRACE: + case SDL_LOG_PRIORITY_VERBOSE: + case SDL_LOG_PRIORITY_DEBUG: + LL_DEBUGS("SDL") << "log='" << message << "'" << LL_ENDL; + break; + case SDL_LOG_PRIORITY_INFO: + LL_INFOS("SDL") << "log='" << message << "'" << LL_ENDL; + break; + case SDL_LOG_PRIORITY_WARN: + case SDL_LOG_PRIORITY_ERROR: + case SDL_LOG_PRIORITY_CRITICAL: + LL_WARNS("SDL") << "log='" << message << "'" << LL_ENDL; + break; + case SDL_LOG_PRIORITY_INVALID: + default: + break; + } +} + +void init_sdl(const std::string& app_name) +{ +#ifndef LL_SDL_APP + if (!gSDLMainHandled) + { + SDL_SetMainReady(); + } +#endif + + SDL_SetLogOutputFunction(&sdl_logger, nullptr); + + const int c_sdl_version = SDL_VERSION; + LL_INFOS() << "Compiled against SDL " + << SDL_VERSIONNUM_MAJOR(c_sdl_version) << "." + << SDL_VERSIONNUM_MINOR(c_sdl_version) << "." + << SDL_VERSIONNUM_MICRO(c_sdl_version) << LL_ENDL; + const int r_sdl_version = SDL_GetVersion(); + LL_INFOS() << "Running with SDL " + << SDL_VERSIONNUM_MAJOR(r_sdl_version) << "." + << SDL_VERSIONNUM_MINOR(r_sdl_version) << "." + << SDL_VERSIONNUM_MICRO(r_sdl_version) << LL_ENDL; + +#if LL_WINDOWS && defined(LL_SDL_WINDOW) + Uint32 style = 0; +#if defined(CS_BYTEALIGNCLIENT) && defined(CS_OWNDC) + style = (CS_BYTEALIGNCLIENT | CS_OWNDC); +#endif + SDL_RegisterApp(app_name.c_str(), style, nullptr); +#endif + +#if LL_SDL_WINDOW + // For linux we SDL_INIT_VIDEO and _AUDIO + std::initializer_list<std::tuple< char const*, char const * > > hintList = + { + {SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR,"0"}, + {SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH,"1"}, + {SDL_HINT_MOUSE_EMULATE_WARP_WITH_RELATIVE,"0"}, + {SDL_HINT_MOUSE_RELATIVE_WARP_MOTION,"1"}, + {SDL_HINT_KEYCODE_OPTIONS,"french_numbers,latin_letters"} + }; + + for (auto hint: hintList) + { + SDL_SetHint(std::get<0>(hint), std::get<1>(hint)); + } + + std::initializer_list<std::tuple<uint32_t, char const*, bool>> initList= + { + {SDL_INIT_VIDEO,"SDL_INIT_VIDEO", true}, + {SDL_INIT_JOYSTICK,"SDL_INIT_JOYSTICK", true}, + {SDL_INIT_GAMEPAD,"SDL_INIT_GAMEPAD", true}, + }; +#else + // For non-linux platforms we still SDL_INIT_VIDEO because it is a pre-requisite + // for SDL_INIT_GAMECONTROLLER. + std::initializer_list<std::tuple<uint32_t, char const*, bool>> initList= + { + {SDL_INIT_VIDEO,"SDL_INIT_VIDEO", false}, + }; +#endif // LL_LINUX + // We SDL_INIT_GAMECONTROLLER later in the startup process to make it + // more likely we'll catch initial SDL_CONTROLLERDEVICEADDED events. + + for (auto subSystem : initList) + { + if (!SDL_InitSubSystem(std::get<0>(subSystem))) + { + LL_WARNS() << "SDL_InitSubSystem for " << std::get<1>(subSystem) << " failed " << SDL_GetError() << LL_ENDL; + + if (std::get<2>(subSystem)) + { + OSMessageBox("SDL_Init() failure", "error", OSMB_OK); + return; + } + } + } +} + +void quit_sdl() +{ +#if LL_WINDOWS && defined(LL_SDL_WINDOW) + SDL_UnregisterApp(); +#endif + SDL_Quit(); +} diff --git a/indra/llwindow/llsdl.h b/indra/llwindow/llsdl.h new file mode 100644 index 0000000000..6c9c9eb07c --- /dev/null +++ b/indra/llwindow/llsdl.h @@ -0,0 +1,34 @@ +/** + * @file llsdl.h + * @brief SDL initialization + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#pragma once + +#include "llpreprocessor.h" + +extern bool gSDLMainHandled; + +void init_sdl(const std::string& app_name); +void quit_sdl(); diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index eb11a28360..2313aeda50 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -29,7 +29,7 @@ #if LL_MESA_HEADLESS #include "llwindowmesaheadless.h" -#elif LL_SDL +#elif LL_SDL_WINDOW #include "llwindowsdl.h" #elif LL_WINDOWS #include "llwindowwin32.h" @@ -39,6 +39,9 @@ #include "llerror.h" #include "llkeyboard.h" +#if LL_SDL_WINDOW && !defined(LL_MESA_HEADLESS) +#include "llsdl.h" +#endif #include "llwindowcallbacks.h" @@ -74,14 +77,15 @@ S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type) LL_WARNS() << "OSMessageBox: " << text << LL_ENDL; #if LL_MESA_HEADLESS // !!! *FIX: (?) return OSBTN_OK; +#elif LL_SDL_WINDOW + result = OSMessageBoxSDL(text, caption, type); #elif LL_WINDOWS result = OSMessageBoxWin32(text, caption, type); #elif LL_DARWIN result = OSMessageBoxMacOSX(text, caption, type); -#elif LL_SDL - result = OSMessageBoxSDL(text, caption, type); #else -#error("OSMessageBox not implemented for this platform!") + LL_WARNS() << "OSMessageBox not implemented for this platform!" << LL_ENDL; + return OSBTN_OK; #endif if (was_visible) @@ -182,12 +186,6 @@ bool LLWindow::dialogColorPicker(F32 *r, F32 *g, F32 *b) return false; } -void *LLWindow::getMediaWindow() -{ - // Default to returning the platform window. - return getPlatformWindow(); -} - bool LLWindow::setSize(LLCoordScreen size) { if (!getMaximized()) @@ -258,12 +256,12 @@ bool LLWindow::copyTextToPrimary(const LLWString &src) // static std::vector<std::string> LLWindow::getDynamicFallbackFontList() { -#if LL_WINDOWS +#if LL_SDL_WINDOW && !LL_MESA_HEADLESS + return LLWindowSDL::getDynamicFallbackFontList(); +#elif LL_WINDOWS return LLWindowWin32::getDynamicFallbackFontList(); #elif LL_DARWIN return LLWindowMacOSX::getDynamicFallbackFontList(); -#elif LL_SDL - return LLWindowSDL::getDynamicFallbackFontList(); #else return std::vector<std::string>(); #endif @@ -272,7 +270,9 @@ std::vector<std::string> LLWindow::getDynamicFallbackFontList() // static std::vector<std::string> LLWindow::getDisplaysResolutionList() { -#if LL_WINDOWS +#if LL_SDL_WINDOW && !LL_MESA_HEADLESS + return LLWindowSDL::getDisplaysResolutionList(); +#elif LL_WINDOWS return LLWindowWin32::getDisplaysResolutionList(); #elif LL_DARWIN return LLWindowMacOSX::getDisplaysResolutionList(); @@ -341,14 +341,17 @@ bool LLSplashScreen::isVisible() // static LLSplashScreen *LLSplashScreen::create() { -#if LL_MESA_HEADLESS || LL_SDL // !!! *FIX: (?) - return 0; +#if LL_MESA_HEADLESS + return nullptr; +#elif LL_SDL_WINDOW + return new LLSplashScreenSDL; #elif LL_WINDOWS return new LLSplashScreenWin32; #elif LL_DARWIN return new LLSplashScreenMacOSX; #else -#error("LLSplashScreen not implemented on this platform!") + LL_WARNS() << ("LLSplashScreen not implemented on this platform!") << LL_ENDL; + return nullptr; #endif } @@ -358,7 +361,9 @@ void LLSplashScreen::show() { if (!gSplashScreenp) { -#if LL_WINDOWS && !LL_MESA_HEADLESS +#if LL_SDL_WINDOW && !LL_MESA_HEADLESS + gSplashScreenp = new LLSplashScreenSDL; +#elif LL_WINDOWS && !LL_MESA_HEADLESS gSplashScreenp = new LLSplashScreenWin32; #elif LL_DARWIN gSplashScreenp = new LLSplashScreenMacOSX; @@ -412,15 +417,19 @@ LLWindow* LLWindowManager::createWindow( { LLWindow* new_window; +#if LL_SDL_WINDOW && !defined(LL_MESA_HEADLESS) + init_sdl(name); +#endif + if (use_gl) { #if LL_MESA_HEADLESS new_window = new LLWindowMesaHeadless(callbacks, title, name, x, y, width, height, flags, fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth); -#elif LL_SDL +#elif LL_SDL_WINDOW new_window = new LLWindowSDL(callbacks, - title, x, y, width, height, flags, + title, name, x, y, width, height, flags, fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); #elif LL_WINDOWS new_window = new LLWindowWin32(callbacks, @@ -461,6 +470,9 @@ bool LLWindowManager::destroyWindow(LLWindow* window) window->close(); sWindowList.erase(window); +#if LL_SDL_WINDOW && !defined(LL_MESA_HEADLESS) + quit_sdl(); +#endif delete window; diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 185940e32d..e9dfa3aba4 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -92,7 +92,7 @@ public: virtual bool setCursorPosition(LLCoordWindow position) = 0; virtual bool getCursorPosition(LLCoordWindow *position) = 0; -#if LL_WINDOWS +#if LL_WINDOWS && !LL_SDL_WINDOW virtual bool getCursorDelta(LLCoordCommon* delta) = 0; #endif virtual bool isWrapMouse() const = 0; @@ -174,9 +174,6 @@ public: // return a platform-specific window reference (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) virtual void *getPlatformWindow() = 0; -// return the platform-specific window reference we use to initialize llmozlib (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) - virtual void *getMediaWindow(); - // control platform's Language Text Input mechanisms. virtual void allowLanguageTextInput(LLPreeditor *preeditor, bool b) {} virtual void setLanguageTextInput( const LLCoordGL & pos ) {}; diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index dc7b833013..8b7b0ef55c 100644 --- a/indra/llwindow/llwindowheadless.h +++ b/indra/llwindow/llwindowheadless.h @@ -60,7 +60,7 @@ public: /*virtual*/ void toggleVSync(bool enable_vsync) override { } /*virtual*/ bool setCursorPosition(LLCoordWindow position) override {return false;} /*virtual*/ bool getCursorPosition(LLCoordWindow *position) override {return false;} -#if LL_WINDOWS +#if LL_WINDOWS && !LL_SDL_WINDOW /*virtual*/ bool getCursorDelta(LLCoordCommon* delta) override { return false; } #endif /*virtual*/ bool isWrapMouse() const override { return true; } diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index d703a84d02..dc8b7504c9 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -36,11 +36,6 @@ #include <ApplicationServices/ApplicationServices.h> #include <OpenGL/OpenGL.h> -// AssertMacros.h does bad things. -#include "fix_macros.h" -#undef verify -#undef require - class LLWindowMacOSX : public LLWindow { public: diff --git a/indra/llwindow/llwindowmesaheadless.h b/indra/llwindow/llwindowmesaheadless.h index 0bf8c46a30..47cd6320b1 100644 --- a/indra/llwindow/llwindowmesaheadless.h +++ b/indra/llwindow/llwindowmesaheadless.h @@ -30,70 +30,75 @@ #if LL_MESA_HEADLESS #include "llwindow.h" -#include "GL/glu.h" #include "GL/osmesa.h" class LLWindowMesaHeadless : public LLWindow { public: - /*virtual*/ void show() {}; - /*virtual*/ void hide() {}; - /*virtual*/ void close() {}; - /*virtual*/ bool getVisible() {return false;}; - /*virtual*/ bool getMinimized() {return false;}; - /*virtual*/ bool getMaximized() {return false;}; - /*virtual*/ bool maximize() {return false;}; - /*virtual*/ void minimize() {}; - /*virtual*/ void restore() {}; - /*virtual*/ bool getFullscreen() {return false;}; - /*virtual*/ bool getPosition(LLCoordScreen *position) {return false;}; - /*virtual*/ bool getSize(LLCoordScreen *size) {return false;}; - /*virtual*/ bool getSize(LLCoordWindow *size) {return false;}; - /*virtual*/ bool setPosition(LLCoordScreen position) {return false;}; - /*virtual*/ bool setSizeImpl(LLCoordScreen size) {return false;}; - /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool disable_vsync, const LLCoordScreen * const posp = NULL) {return false;}; - /*virtual*/ bool setCursorPosition(LLCoordWindow position) {return false;}; - /*virtual*/ bool getCursorPosition(LLCoordWindow *position) {return false;}; - /*virtual*/ void showCursor() {}; - /*virtual*/ void hideCursor() {}; - /*virtual*/ void showCursorFromMouseMove() {}; - /*virtual*/ void hideCursorUntilMouseMove() {}; - /*virtual*/ bool isCursorHidden() {return false;}; - /*virtual*/ void updateCursor() {}; - //virtual ECursorType getCursor() { return mCurrentCursor; }; - /*virtual*/ void captureMouse() {}; - /*virtual*/ void releaseMouse() {}; - /*virtual*/ void setMouseClipping( bool b ) {}; - /*virtual*/ bool isClipboardTextAvailable() {return false; }; - /*virtual*/ bool pasteTextFromClipboard(LLWString &dst) {return false; }; - /*virtual*/ bool copyTextToClipboard(const LLWString &src) {return false; }; - /*virtual*/ void flashIcon(F32 seconds) {}; - /*virtual*/ F32 getGamma() {return 1.0f; }; - /*virtual*/ bool setGamma(const F32 gamma) {return false; }; // Set the gamma - /*virtual*/ bool restoreGamma() {return false; }; // Restore original gamma table (before updating gamma) - /*virtual*/ void setFSAASamples(const U32 fsaa_samples) { /* FSAA not supported yet on Mesa headless.*/ } - /*virtual*/ U32 getFSAASamples() { return 0; } - //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } - /*virtual*/ void gatherInput() {}; - /*virtual*/ void delayInputProcessing() {}; - /*virtual*/ void swapBuffers(); - /*virtual*/ void restoreGLContext() {}; + void show() override {}; + void hide() override {}; + void close() override {}; + bool getVisible() override {return false;}; + bool getMinimized() override {return false;}; + bool getMaximized() override {return false;}; + bool maximize() override {return false;}; + void minimize() override {}; + void restore() override {}; + bool getFullscreen() {return false;}; + bool getPosition(LLCoordScreen *position) override {return false;}; + bool getSize(LLCoordScreen *size) override {return false;}; + bool getSize(LLCoordWindow *size) override {return false;}; + bool setPosition(LLCoordScreen position) override {return false;}; + bool setSizeImpl(LLCoordScreen size) override {return false;}; + bool switchContext(bool fullscreen, const LLCoordScreen &size, bool disable_vsync, const LLCoordScreen * const posp = NULL) override {return false;}; + bool setCursorPosition(LLCoordWindow position) override {return false;}; + bool getCursorPosition(LLCoordWindow *position) override {return false;}; + bool isWrapMouse() const override { return true; } + void showCursor() override {}; + void hideCursor() override {}; + void showCursorFromMouseMove() override {}; + void hideCursorUntilMouseMove() override {}; + bool isCursorHidden() override {return false;}; + void updateCursor() override {}; + //virtual ECursorType getCursor() override { return mCurrentCursor; }; + void captureMouse() override {}; + void releaseMouse() override {}; + void setMouseClipping( bool b ) override {}; + bool isClipboardTextAvailable() override {return false; }; + bool pasteTextFromClipboard(LLWString &dst) override {return false; }; + bool copyTextToClipboard(const LLWString &src) override {return false; }; + void flashIcon(F32 seconds) override {}; + F32 getGamma() override {return 1.0f; }; + bool setGamma(const F32 gamma) override {return false; }; // Set the gamma + bool restoreGamma() override {return false; }; // Restore original gamma table (before updating gamma) + void setFSAASamples(const U32 fsaa_samples) override { /* FSAA not supported yet on Mesa headless.*/ } + U32 getFSAASamples() override { return 0; } + //virtual ESwapMethod getSwapMethod() override { return mSwapMethod; } + void gatherInput() override {}; + void delayInputProcessing() override {}; + void swapBuffers() override; + + void* createSharedContext()override{return nullptr;}; + void makeContextCurrent(void* context)override{}; + void destroySharedContext(void* context)override{}; + void toggleVSync(bool enable_vsync) override {}; + bool setSizeImpl(LLCoordWindow size) override { return false; }; // handy coordinate space conversion routines - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to) { return false; }; + bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override { return false; }; + bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override { return false; }; + bool convertCoords(LLCoordWindow from, LLCoordGL *to) override { return false; }; + bool convertCoords(LLCoordGL from, LLCoordWindow *to) override { return false; }; + bool convertCoords(LLCoordScreen from, LLCoordGL *to) override { return false; }; + bool convertCoords(LLCoordGL from, LLCoordScreen *to) override { return false; }; - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) { return NULL; }; - /*virtual*/ F32 getNativeAspectRatio() { return 1.0f; }; - /*virtual*/ F32 getPixelAspectRatio() { return 1.0f; }; - /*virtual*/ void setNativeAspectRatio(F32 ratio) {} + LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override { return NULL; }; + F32 getNativeAspectRatio() override { return 1.0f; }; + F32 getPixelAspectRatio() override { return 1.0f; }; + void setNativeAspectRatio(F32 ratio) override {} - /*virtual*/ void *getPlatformWindow() { return 0; }; - /*virtual*/ void bringToFront() {}; + void *getPlatformWindow() override { return 0; }; + void bringToFront() override {}; LLWindowMesaHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, @@ -112,9 +117,9 @@ public: LLSplashScreenMesaHeadless() {}; virtual ~LLSplashScreenMesaHeadless() {}; - /*virtual*/ void showImpl() {}; - /*virtual*/ void updateImpl(const std::string& mesg) {}; - /*virtual*/ void hideImpl() {}; + void showImpl() override {}; + void updateImpl(const std::string& mesg) override {}; + void hideImpl() override {}; }; diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index 05be319c0b..2d8a74c782 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -25,8 +25,6 @@ * $/LicenseInfo$ */ -#if LL_SDL - #include "linden_common.h" #include "llwindowsdl.h" @@ -39,197 +37,84 @@ #include "llstring.h" #include "lldir.h" #include "llfindlocale.h" +#include "llpreeditor.h" +#include "llsdl.h" -#if LL_GTK -extern "C" { -# include "gtk/gtk.h" -} -#include <locale.h> -#endif // LL_GTK +#if LL_LINUX +#ifdef LL_GLIB +#include <glib.h> +#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 <unistd.h> -# include <sys/types.h> -# include <sys/wait.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdio.h> + +#if LL_X11 +LLWindowSDL::X11_DATA LLWindowSDL::sX11Data = {}; +#endif +#if LL_WAYLAND +LLWindowSDL::WAYLAND_DATA LLWindowSDL::sWaylandData = {}; +#endif #endif // LL_LINUX -extern bool gDebugWindowProc; +#if LL_DARWIN +#include <OpenGL/OpenGL.h> +#include <Carbon/Carbon.h> +#include <CoreServices/CoreServices.h> +#include <CoreGraphics/CGDisplayConfiguration.h> -const S32 MAX_NUM_RESOLUTIONS = 200; +bool LLWindowSDL::sUseMultGL = false; +#endif + +bool gHiDPISupport = true; -// static variable for ATI mouse cursor crash work-around: -static bool ATIbug = false; +const S32 MAX_NUM_RESOLUTIONS = 200; +const S32 DEFAULT_REFRESH_RATE = 60; // // LLWindowSDL // -#if LL_X11 -# include <X11/Xutil.h> -#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_GTK -// Lazily initialize and check the runtime GTK version for goodness. -// static -bool LLWindowSDL::ll_try_gtk_init(void) -{ - static bool done_gtk_diag = false; - static bool gtk_is_good = false; - static bool done_setlocale = false; - static bool tried_gtk_init = false; - - if (!done_setlocale) - { - LL_INFOS() << "Starting GTK Initialization." << LL_ENDL; - maybe_lock_display(); - gtk_disable_setlocale(); - maybe_unlock_display(); - done_setlocale = true; - } - - if (!tried_gtk_init) - { - tried_gtk_init = true; - if (!g_thread_supported ()) g_thread_init (NULL); - maybe_lock_display(); - gtk_is_good = gtk_init_check(NULL, NULL); - maybe_unlock_display(); - if (!gtk_is_good) - LL_WARNS() << "GTK Initialization failed." << LL_ENDL; - } - - if (gtk_is_good && !done_gtk_diag) - { - LL_INFOS() << "GTK Initialized." << LL_ENDL; - LL_INFOS() << "- Compiled against GTK version " - << GTK_MAJOR_VERSION << "." - << GTK_MINOR_VERSION << "." - << GTK_MICRO_VERSION << LL_ENDL; - LL_INFOS() << "- Running against GTK version " - << gtk_major_version << "." - << gtk_minor_version << "." - << gtk_micro_version << LL_ENDL; - maybe_lock_display(); - const gchar* gtk_warning = gtk_check_version( - GTK_MAJOR_VERSION, - GTK_MINOR_VERSION, - GTK_MICRO_VERSION); - maybe_unlock_display(); - if (gtk_warning) - { - LL_WARNS() << "- GTK COMPATIBILITY WARNING: " << - gtk_warning << LL_ENDL; - gtk_is_good = false; - } else { - LL_INFOS() << "- GTK version is good." << LL_ENDL; - } - - done_gtk_diag = true; - } - - return gtk_is_good; -} -#endif // LL_GTK - - -#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 - +static LLWindowSDL *gWindowImplementation = nullptr; 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, - bool ignore_pixel_depth, U32 fsaa_samples) - : LLWindow(callbacks, fullscreen, flags), - Lock_Display(NULL), - Unlock_Display(NULL), mGamma(1.0f) + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, + S32 height, U32 flags, + bool fullscreen, bool clearBg, + bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples) + : LLWindow(callbacks, fullscreen, flags), + mGamma(1.0f), mFlashing(false) { + SDL_GL_LoadLibrary(nullptr); + // 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; - 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 - -#if LL_GTK - // We MUST be the first to initialize GTK so that GTK doesn't get badly - // initialized with a non-C locale and cause lots of serious random - // weirdness. - ll_try_gtk_init(); -#endif // LL_GTK // Assume 4:3 aspect ratio until we know better - mOriginalAspectRatio = 1024.0 / 768.0; + mNativeAspectRatio = 1024.f / 768.f; if (title.empty()) - mWindowTitle = "SDL Window"; // *FIX: (?) + mWindowTitle = "Second Life"; 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)) + if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) { + gGLManager.initWGL(); gGLManager.initGL(); //start with arrow cursor @@ -241,14 +126,6 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, // Stash an object pointer for OSMessageBox() gWindowImplementation = this; - -#if LL_X11 - mFlashing = false; -#endif // LL_X11 - - mKeyScanCode = 0; - mKeyVirtualKey = 0; - mKeyModifiers = KMOD_NONE; } static SDL_Surface *Load_BMP_Resource(const char *basename) @@ -258,480 +135,377 @@ static SDL_Surface *Load_BMP_Resource(const char *basename) // 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); + 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) +void LLWindowSDL::setTitle(const std::string title) { - 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' + SDL_SetWindowTitle( mWindow, title.c_str() ); } -static int x11_detect_VRAM_kb() +void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) { - 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'; - } + LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; - // *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) + // If the requested width or height is 0, find the best default for the monitor. + if(width == 0 || height == 0) { - LL_INFOS() << "Looking in " << fname - << " for VRAM info..." << LL_ENDL; - rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); - fclose(fp); - if (0 == rtn) + // 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 != nullptr) { - fp = fopen(fname.c_str(), "r"); - if (fp) + F32 closestAspect = 0; + U32 closestHeight = 0; + U32 closestWidth = 0; + + LL_INFOS() << "createContext: searching for a display mode, original aspect is " << mNativeAspectRatio << LL_ENDL; + + for(S32 i=0; i < resolutionCount; i++) { - rtn = x11_detect_VRAM_kb_fp(fp, ": Video RAM: "); - fclose(fp); - if (0 == rtn) + 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 - mNativeAspectRatio) < fabs(closestAspect - mNativeAspectRatio))) { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); - fclose(fp); - } + 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; } } - else + + if(width == 0 || height == 0) { - 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; - } + // Mode search failed for some reason. Use the old-school default. + width = 1024; + height = 768; } - return rtn; } -#endif // LL_X11 -bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool disable_vsync) +bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync) { - //bool glneedsinit = false; - - LL_INFOS() << "createContext, fullscreen=" << fullscreen << - " size=" << width << "x" << height << LL_ENDL; + LL_INFOS() << "createContext, fullscreen=" << fullscreen << " size=" << width << "x" << height << LL_ENDL; // captures don't survive contexts mGrabbyKeyFlags = 0; - mReallyCapturedCount = 0; - if (SDL_Init(SDL_INIT_VIDEO) < 0) - { - LL_INFOS() << "sdl_init() failed! " << SDL_GetError() << LL_ENDL; - setupFailure("sdl_init() failure, window creation error", "error", OSMB_OK); - return false; - } + if (width == 0) + width = 1024; + if (height == 0) + width = 768; + if (x == 0) + x = SDL_WINDOWPOS_UNDEFINED; + if (y == 0) + y = SDL_WINDOWPOS_UNDEFINED; - 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; - const SDL_version *r_sdl_version; - r_sdl_version = SDL_Linked_Version(); - LL_INFOS() << " Running against SDL " - << int(r_sdl_version->major) << "." - << int(r_sdl_version->minor) << "." - << int(r_sdl_version->patch) << LL_ENDL; + mFullscreen = fullscreen; + + // Setup default backing colors + GLint redBits{8}, greenBits{8}, blueBits{8}, alphaBits{8}; + GLint depthBits{24}, stencilBits{8}; + + 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_ALPHA_SIZE, alphaBits); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthBits); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencilBits); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - const SDL_VideoInfo *video_info = SDL_GetVideoInfo( ); - if (!video_info) + SDL_GLContextFlag context_flags{}; + if(LLRender::sGLCoreProfile) { - LL_INFOS() << "SDL_GetVideoInfo() failed! " << SDL_GetError() << LL_ENDL; - setupFailure("SDL_GetVideoInfo() failed, Window creation error", "Error", OSMB_OK); - return false; + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); +#if LL_DARWIN + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + context_flags |= SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG; +#endif } - if (video_info->current_h > 0) + if (gDebugGL) { - mOriginalAspectRatio = (float)video_info->current_w / (float)video_info->current_h; - LL_INFOS() << "Original aspect ratio was " << video_info->current_w << ":" << video_info->current_h << "=" << mOriginalAspectRatio << LL_ENDL; + context_flags |= SDL_GL_CONTEXT_DEBUG_FLAG; } - SDL_EnableUNICODE(1); - SDL_WM_SetCaption(mWindowTitle.c_str(), mWindowTitle.c_str()); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, context_flags); + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); - // Set the application icon. - SDL_Surface *bmpsurface; - bmpsurface = Load_BMP_Resource("ll_icon.BMP"); - if (bmpsurface) + if(mFullscreen) { - // This attempts to give a black-keyed mask to the icon. - SDL_SetColorKey(bmpsurface, - SDL_SRCCOLORKEY, - SDL_MapRGB(bmpsurface->format, 0,0,0) ); - SDL_WM_SetIcon(bmpsurface, NULL); - // The SDL examples cheerfully avoid freeing the icon - // surface, but I'm betting that's leaky. - SDL_FreeSurface(bmpsurface); - bmpsurface = NULL; + tryFindFullscreenSize(width, height); } - // note: these SetAttributes make Tom's 9600-on-AMD64 fail to - // get a visual, but it's broken anyway when it does, and without - // these SetAttributes we might easily get an avoidable substandard - // visual to work with on most other machines. - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, (bits <= 16) ? 16 : 24); - // We need stencil support for a few (minor) things. - if (!getenv("LL_GL_NO_STENCIL")) - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, (bits <= 16) ? 1 : 8); - - // *FIX: try to toggle vsync here? - - mFullscreen = fullscreen; - - int sdlflags = SDL_OPENGL | SDL_RESIZABLE | SDL_ANYFORMAT; - - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, mWindowTitle.c_str()); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, x); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, y); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, width); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, height); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, true); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, mFullscreen); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN, true); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, gHiDPISupport); - if (mFSAASamples > 0) + mWindow = SDL_CreateWindowWithProperties(props); + if (mWindow == nullptr) { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mFSAASamples); + LL_WARNS() << "Window creation failure. SDL: " << SDL_GetError() << LL_ENDL; + setupFailure("Window creation error", "Error", OSMB_OK); + SDL_DestroyProperties(props); + return false; } + SDL_DestroyProperties(props); // Free properties once window is created - mSDLFlags = sdlflags; + // Create the context + mContext = SDL_GL_CreateContext(mWindow); + if(!mContext) + { + LL_WARNS() << "Cannot create GL context " << SDL_GetError() << LL_ENDL; + setupFailure("GL Context creation error", "Error", OSMB_OK); + return false; + } - if (mFullscreen) + if (!SDL_GL_MakeCurrent(mWindow, mContext)) { - LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; + LL_WARNS() << "Failed to make context current. SDL: " << SDL_GetError() << LL_ENDL; + setupFailure("GL Context failed to set current failure", "Error", OSMB_OK); + return false; + } - // If the requested width or height is 0, find the best default for the monitor. - if((width == 0) || (height == 0)) + const SDL_DisplayMode* displayMode = SDL_GetCurrentDisplayMode(SDL_GetDisplayForWindow(mWindow)); + if(displayMode) + { + mRefreshRate = ll_round(displayMode->refresh_rate); + mNativeAspectRatio = ((F32)displayMode->w) / ((F32)displayMode->h); + if(mFullscreen) { - // 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; + mFullscreenWidth = displayMode->w; + mFullscreenHeight = displayMode->h; + mFullscreenRefresh = ll_round(displayMode->refresh_rate); - 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; - } + LL_INFOS() << "Running at " << mFullscreenWidth + << "x" << mFullscreenHeight + << " @ " << mFullscreenRefresh + << LL_ENDL; } - - if((width == 0) || (height == 0)) + } + else + { + LL_WARNS() << "Failed to get current display mode and refresh rate" << LL_ENDL; + mRefreshRate = 0; + mNativeAspectRatio = 1024.f / 768.f; + if(mFullscreen) // Fallback to window size { - // Mode search failed for some reason. Use the old-school default. - width = 1024; - height = 768; + SDL_GetWindowSize(mWindow, &mFullscreenWidth, &mFullscreenHeight); + mFullscreenRefresh = -1; } + } - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN); - if (!mWindow && bits > 16) - { - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN); - } + if(mRefreshRate == 0) // We failed to get a valid refresh rate above + { + mRefreshRate = DEFAULT_REFRESH_RATE; + } - if (mWindow) - { - mFullscreen = true; - mFullscreenWidth = mWindow->w; - mFullscreenHeight = mWindow->h; - mFullscreenBits = mWindow->format->BitsPerPixel; - mFullscreenRefresh = -1; + /* Grab the window manager specific information */ +#if LL_LINUX + if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) + { + LL_INFOS() << "Running under X11" << LL_ENDL; + mServerProtocol = X11; - LL_INFOS() << "Running at " << mFullscreenWidth - << "x" << mFullscreenHeight - << "x" << mFullscreenBits - << " @ " << mFullscreenRefresh - << LL_ENDL; - } - else + gGLManager.mIsX11 = true; + +#if LL_X11 + sX11Data.xdisplay = (Display *)SDL_GetPointerProperty(SDL_GetWindowProperties(mWindow), SDL_PROP_WINDOW_X11_DISPLAY_POINTER, nullptr); + sX11Data.xwindow = (Window)SDL_GetNumberProperty(SDL_GetWindowProperties(mWindow), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); + sX11Data.xscreen = (int)SDL_GetNumberProperty(SDL_GetWindowProperties(mWindow), SDL_PROP_WINDOW_X11_SCREEN_NUMBER, -1); + if (sX11Data.xdisplay && sX11Data.xwindow) { - 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); } - } +#endif - if(!mFullscreen && (mWindow == NULL)) + gGLManager.initGLX(); + } + else if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) { - if (width == 0) - width = 1024; - if (height == 0) - width = 768; + LL_INFOS() << "Running under Wayland" << LL_ENDL; + mServerProtocol = Wayland; - LL_INFOS() << "createContext: creating window " << width << "x" << height << "x" << bits << LL_ENDL; - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); - if (!mWindow && bits > 16) - { - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); - } + gGLManager.mIsWayland = true; - if (!mWindow) +#if LL_WAYLAND + sWaylandData.display = (struct wl_display *)SDL_GetPointerProperty(SDL_GetWindowProperties(mWindow), SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, nullptr); + sWaylandData.surface = (struct wl_surface *)SDL_GetPointerProperty(SDL_GetWindowProperties(mWindow), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr); + if (sWaylandData.display && sWaylandData.surface) { - LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL; - setupFailure("Window creation error", "Error", OSMB_OK); - return false; } - } else if (!mFullscreen && (mWindow != NULL)) - { - LL_INFOS() << "createContext: SKIPPING - !fullscreen, but +mWindow " << width << "x" << height << "x" << bits << LL_ENDL; - } +#endif - // 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 = video_info->video_mem / 1024; - if (gGLManager.mVRAM != 0) + gGLManager.initEGL(); + + // If set (XWayland) remove DISPLAY, this will prompt dullahan to also use Wayland + if(getenv("DISPLAY")) { - LL_INFOS() << "SDL detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; + unsetenv("DISPLAY"); } } - // 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); - - GLint depthBits, stencilBits, redBits, greenBits, blueBits, alphaBits; +#endif - glGetIntegerv(GL_RED_BITS, &redBits); - glGetIntegerv(GL_GREEN_BITS, &greenBits); - glGetIntegerv(GL_BLUE_BITS, &blueBits); - glGetIntegerv(GL_ALPHA_BITS, &alphaBits); - glGetIntegerv(GL_DEPTH_BITS, &depthBits); - glGetIntegerv(GL_STENCIL_BITS, &stencilBits); + 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; + 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); + "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 0 // *FIX: we're going to brave it for now... - if (alphaBits < 8) + LL_PROFILER_GPU_CONTEXT; + + // Enable vertical sync + toggleVSync(enable_vsync); + +#if LL_DARWIN + setUseMultGL(sUseMultGL); + + // Get vram via CGL on macos + gGLManager.mVRAM = getVramSize(); +#endif + + // Set the application icon. + SDL_Surface* bmpsurface = Load_BMP_Resource("ll_icon.BMP"); + if (bmpsurface) { - close(); - setupFailure( - "Second Life is unable to run because it can't get an 8 bit alpha\n" - "channel. Usually this is due to video card driver issues.\n" - "Please make sure you have the latest video card drivers installed.\n" - "Also be sure your monitor is set to True Color (32-bit) in\n" - "Control Panels -> Display -> Settings.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); - return false; + SDL_SetWindowIcon(mWindow, bmpsurface); + SDL_DestroySurface(bmpsurface); + bmpsurface = nullptr; } -#endif -#if LL_X11 - /* Grab the window manager specific information */ - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - if ( SDL_GetWMInfo(&info) ) + SDL_StartTextInput(mWindow); + return true; +} + +void* LLWindowSDL::createSharedContext() +{ + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, "Second Life OSR Utility"); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, 1); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, 1); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, false); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN, true); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN, false); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_UTILITY_BOOLEAN, true); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, gHiDPISupport); + + auto osr_window = SDL_CreateWindowWithProperties(props); + if (osr_window == nullptr) { - /* Save the information for later use */ - if ( info.subsystem == SDL_SYSWM_X11 ) - { - mSDL_Display = info.info.x11.display; - mSDL_XWindowID = info.info.x11.wmwindow; - Lock_Display = info.info.x11.lock_func; - Unlock_Display = info.info.x11.unlock_func; - } - else - { - LL_WARNS() << "We're not running under X11? Wild." - << LL_ENDL; - } + SDL_DestroyProperties(props); + return nullptr; } - else + SDL_DestroyProperties(props); // Free properties once window is created + SDL_GLContext pContext = SDL_GL_CreateContext(osr_window); + + // Hack to ensure main window context is bound + SDL_GL_MakeCurrent(mWindow, mContext); + + if (!pContext) { - LL_WARNS() << "We're not running under any known WM. Wild." - << LL_ENDL; + LL_WARNS() << "Creating shared OpenGL context failed!" << LL_ENDL; + SDL_DestroyWindow(osr_window); + return nullptr; } -#endif // LL_X11 + { + LLMutexLock osr_lock(&mOSRMutex); + mOSRContexts.emplace(pContext, osr_window); + } - //make sure multisampling is disabled by default - glDisable(GL_MULTISAMPLE_ARB); + LL_DEBUGS() << "Creating shared OpenGL context successful!" << LL_ENDL; + return (void*)pContext; +} - // We need to do this here, once video is init'd - if (-1 == SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, - SDL_DEFAULT_REPEAT_INTERVAL)) - LL_WARNS() << "Couldn't enable key-repeat: " << SDL_GetError() <<LL_ENDL; +void LLWindowSDL::makeContextCurrent(void* contextPtr) +{ + LLMutexLock osr_lock(&mOSRMutex); + auto it = mOSRContexts.find((SDL_GLContext)contextPtr); + if(it != mOSRContexts.end()) + { + SDL_GL_MakeCurrent((SDL_Window*)it->second, (SDL_GLContext)it->first); + } + LL_PROFILER_GPU_CONTEXT; +} - // Don't need to get the current gamma, since there's a call that restores it to the system defaults. - return true; +void LLWindowSDL::destroySharedContext(void* contextPtr) +{ + LLMutexLock osr_lock(&mOSRMutex); + auto it = mOSRContexts.find((SDL_GLContext)contextPtr); + if(it != mOSRContexts.end()) + { + SDL_GL_DestroyContext((SDL_GLContext)it->first); + mDeadOSRWindows.push_back((SDL_Window*)it->second); + } } +void LLWindowSDL::toggleVSync(bool enable_vsync) +{ + if (!enable_vsync) + { + LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL; + SDL_GL_SetSwapInterval(0); + } + else + { + LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL; + SDL_GL_SetSwapInterval(1); + } +} // 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) +bool LLWindowSDL::switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp) { const bool needsRebuild = true; // Just nuke the context and start over. bool result = true; @@ -741,9 +515,10 @@ bool LLWindowSDL::switchContext(bool fullscreen, const LLCoordScreen &size, bool if(needsRebuild) { destroyContext(); - result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); + result = createContext(0, 0, size.mX, size.mY, 32, fullscreen, enable_vsync); if (result) { + gGLManager.initWGL(); gGLManager.initGL(); //start with arrow cursor @@ -761,69 +536,96 @@ void LLWindowSDL::destroyContext() { LL_INFOS() << "destroyContext begins" << LL_ENDL; -#if LL_X11 - mSDL_Display = NULL; - mSDL_XWindowID = None; - Lock_Display = NULL; - Unlock_Display = NULL; -#endif // LL_X11 + { + LLMutexLock osr_lock(&mOSRMutex); + for(SDL_Window* pWindow : mDeadOSRWindows) + { + SDL_DestroyWindow(pWindow); + } + mDeadOSRWindows.clear(); + } + + // Stop unicode input + SDL_StopTextInput(mWindow); // 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; + LL_INFOS() << "Destroying SDL cursors" << LL_ENDL; + quitCursors(); + + if (mContext) + { + LL_INFOS() << "Destroying SDL GL Context" << LL_ENDL; + SDL_GL_DestroyContext(mContext); + mContext = nullptr; + } + else + { + LL_INFOS() << "SDL GL Context already destroyed" << LL_ENDL; + } + + if (mWindow) + { + LL_INFOS() << "Destroying SDL Window" << LL_ENDL; + SDL_DestroyWindow(mWindow); + mWindow = nullptr; + } + else + { + LL_INFOS() << "SDL Window already destroyed" << LL_ENDL; + } + LL_INFOS() << "destroyContext end" << LL_ENDL; } LLWindowSDL::~LLWindowSDL() { - quitCursors(); destroyContext(); - if(mSupportedResolutions != NULL) - { - delete []mSupportedResolutions; - } + delete[] mSupportedResolutions; - gWindowImplementation = NULL; + gWindowImplementation = nullptr; } void LLWindowSDL::show() { - // *FIX: What to do with SDL? + if (mWindow) + { + SDL_ShowWindow(mWindow); + SDL_RaiseWindow(mWindow); + } } void LLWindowSDL::hide() { - // *FIX: What to do with SDL? + if (mWindow) + { + SDL_HideWindow(mWindow); + } } -//virtual void LLWindowSDL::minimize() { - // *FIX: What to do with SDL? + if (mWindow) + { + SDL_MinimizeWindow(mWindow); + } } -//virtual void LLWindowSDL::restore() { - // *FIX: What to do with SDL? + if (mWindow) + { + SDL_RestoreWindow(mWindow); + } } - // 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(); @@ -833,134 +635,127 @@ void LLWindowSDL::close() bool LLWindowSDL::isValid() { - return (mWindow != NULL); + return mWindow != nullptr; } bool LLWindowSDL::getVisible() { - bool result = false; - - // *FIX: This isn't really right... - // Then what is? + bool result = true; if (mWindow) { - result = true; + SDL_WindowFlags flags = SDL_GetWindowFlags(mWindow); + if (flags & SDL_WINDOW_HIDDEN) + { + result = false; + } } - - return(result); + return result; } bool LLWindowSDL::getMinimized() { bool result = false; - - if (mWindow && (1 == mIsMinimized)) + if (mWindow) { - result = true; + SDL_WindowFlags flags = SDL_GetWindowFlags(mWindow); + if (flags & SDL_WINDOW_MINIMIZED) + { + result = true; + } } - return(result); + return result; } bool LLWindowSDL::getMaximized() { bool result = false; - if (mWindow) { - // TODO + SDL_WindowFlags flags = SDL_GetWindowFlags(mWindow); + if (flags & SDL_WINDOW_MAXIMIZED) + { + result = true; + } } - return(result); + return result; } bool LLWindowSDL::maximize() { - // TODO + if (mWindow) + { + SDL_MaximizeWindow(mWindow); + return true; + } 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; + if (mWindow) + { + SDL_GetWindowPosition(mWindow, &position->mX, &position->mY); + return true; + } + return false; } bool LLWindowSDL::getSize(LLCoordScreen *size) { if (mWindow) { - size->mX = mWindow->w; - size->mY = mWindow->h; - return (true); + SDL_GetWindowSize(mWindow, &size->mX, &size->mY); + return true; } - return (false); + return false; } bool LLWindowSDL::getSize(LLCoordWindow *size) { if (mWindow) { - size->mX = mWindow->w; - size->mY = mWindow->h; - return (true); + SDL_GetWindowSizeInPixels(mWindow, &size->mX, &size->mY); + return true; } - return (false); + return false; } bool LLWindowSDL::setPosition(const LLCoordScreen position) { - if(mWindow) + if (mWindow) { - // *FIX: (?) - //MacMoveWindow(mWindow, position.mX, position.mY, false); + SDL_SetWindowPosition(mWindow, position.mX, position.mY); + return true; } - return true; + return false; } -bool LLWindowSDL::setSizeImpl(const LLCoordScreen size) +template< typename T > bool setSizeImpl( const T& newSize, SDL_Window *pWin ) { - if(mWindow) - { - // Push a resize event onto SDL's queue - we'll handle it - // when it comes out again. - SDL_Event event; - event.type = SDL_VIDEORESIZE; - event.resize.w = size.mX; - event.resize.h = size.mY; - SDL_PushEvent(&event); // copied into queue + if( !pWin ) + return false; - return true; - } + SDL_WindowFlags winFlags = SDL_GetWindowFlags(pWin); - return false; + if( winFlags & SDL_WINDOW_MAXIMIZED) + SDL_RestoreWindow(pWin); + + SDL_SetWindowSize(pWin, newSize.mX, newSize.mY); + return true; } -bool LLWindowSDL::setSizeImpl(const LLCoordWindow size) +bool LLWindowSDL::setSizeImpl(const LLCoordScreen size) { - if(mWindow) - { - // Push a resize event onto SDL's queue - we'll handle it - // when it comes out again. - SDL_Event event; - event.type = SDL_VIDEORESIZE; - event.resize.w = size.mX; - event.resize.h = size.mY; - SDL_PushEvent(&event); // copied into queue - - return true; - } + return ::setSizeImpl( size, mWindow ); +} - return false; +bool LLWindowSDL::setSizeImpl(const LLCoordWindow size) +{ + return ::setSizeImpl( size, mWindow ); } @@ -968,8 +763,9 @@ void LLWindowSDL::swapBuffers() { if (mWindow) { - SDL_GL_SwapBuffers(); + SDL_GL_SwapWindow(mWindow); } + LL_PROFILER_GPU_COLLECT; } U32 LLWindowSDL::getFSAASamples() @@ -984,22 +780,23 @@ void LLWindowSDL::setFSAASamples(const U32 samples) F32 LLWindowSDL::getGamma() { - return 1/mGamma; + return 1.f / 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); + if (mWindow) + { + mGamma = gamma; + if (mGamma == 0) + mGamma = 0.1f; + mGamma = 1.f / mGamma; + } return true; } @@ -1008,12 +805,13 @@ bool LLWindowSDL::isCursorHidden() return mCursorHidden; } - - // Constrains the mouse to the window. -void LLWindowSDL::setMouseClipping( bool b ) +void LLWindowSDL::setMouseClipping(bool b) { - //SDL_WM_GrabInput(b ? SDL_GRAB_ON : SDL_GRAB_OFF); + if (mWindow) + { + SDL_SetWindowMouseGrab(mWindow, b); + } } // virtual @@ -1021,38 +819,16 @@ void LLWindowSDL::setMinSize(U32 min_width, U32 min_height, bool enforce_immedia { 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 + if (mWindow && min_width > 0 && min_height > 0) + { + SDL_SetWindowMinimumSize(mWindow, mMinWindowWidth, mMinWindowHeight); + } } 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_WarpMouse(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; + SDL_WarpMouseInWindow(mWindow, (F32)position.mX, (F32)position.mY); + return true; } bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) @@ -1060,54 +836,34 @@ bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) //Point cursor_point; LLCoordScreen screen_pos; - //GetMouse(&cursor_point); - int x, y; + float x, y; SDL_GetMouseState(&x, &y); - screen_pos.mX = x; - screen_pos.mY = y; + screen_pos.mX = (S32)x; + screen_pos.mY = (S32)y; return convertCoords(screen_pos, position); } - F32 LLWindowSDL::getNativeAspectRatio() { -#if 0 + if (mOverrideAspectRatio > 0.f) + { + return mOverrideAspectRatio; + } + else if (mNativeAspectRatio > 0.f) + { + // we grabbed this value at startup, based on the user's desktop settings + return mNativeAspectRatio; + } + // RN: this hack presumes that the largest supported resolution is monitor-limited // and that pixels in that mode are square, therefore defining the native aspect ratio // of the monitor...this seems to work to a close approximation for most CRTs/LCDs S32 num_resolutions; LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); - return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); - //rn: AC -#endif - - // 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() @@ -1130,104 +886,26 @@ F32 LLWindowSDL::getPixelAspectRatio() // 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_WM_ToggleFullScreen(mWindow); - } - } - } - -#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(); + if (mFullscreen && mWindow ) + SDL_SetWindowFullscreen( mWindow, 0 ); } -#endif // LL_X11 - -#if LL_GTK - // this is a good time to grab some GTK version information for - // diagnostics, if not already done. - ll_try_gtk_init(); -#endif // LL_GTK - - 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_WM_ToggleFullScreen(mWindow); - } - } + if (mFullscreen && 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 !LL_X11 - LL_INFOS() << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; -#else - LL_INFOS() << "X11 LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; + LL_INFOS() << "LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; F32 remaining_time = mFlashTimer.getRemainingTimeF32(); if (remaining_time < seconds) @@ -1235,132 +913,71 @@ void LLWindowSDL::flashIcon(F32 seconds) mFlashTimer.reset(); mFlashTimer.setTimerExpirySec(remaining_time); - x11_set_urgent(true); + SDL_FlashWindow(mWindow, SDL_FLASH_UNTIL_FOCUSED); mFlashing = true; -#endif // LL_X11 } - -#if LL_GTK -bool LLWindowSDL::isClipboardTextAvailable() +void LLWindowSDL::maybeStopFlashIcon() { - if (ll_try_gtk_init()) + if (mFlashing && mFlashTimer.hasExpired()) { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_NONE); - return gtk_clipboard_wait_is_text_available(clipboard) ? - true : false; + mFlashing = false; + SDL_FlashWindow( mWindow, SDL_FLASH_CANCEL ); } - return false; // failure } -bool LLWindowSDL::pasteTextFromClipboard(LLWString &text) +bool LLWindowSDL::isClipboardTextAvailable() { - if (ll_try_gtk_init()) + return SDL_HasClipboardText(); +} + +bool LLWindowSDL::pasteTextFromClipboard(LLWString &dst) +{ + if (isClipboardTextAvailable()) { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_NONE); - gchar * const data = gtk_clipboard_wait_for_text(clipboard); + char* data = SDL_GetClipboardText(); if (data) { - text = LLWString(utf8str_to_wstring(data)); - g_free(data); + dst = LLWString(utf8str_to_wstring(data)); + SDL_free(data); return true; } } - return false; // failure + return false; } -bool LLWindowSDL::copyTextToClipboard(const LLWString &text) +bool LLWindowSDL::copyTextToClipboard(const LLWString& text) { - if (ll_try_gtk_init()) - { - const std::string utf8 = wstring_to_utf8str(text); - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_NONE); - gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); - return true; - } - return false; // failure + const std::string utf8 = wstring_to_utf8str(text); + return SDL_SetClipboardText(utf8.c_str()); } - bool LLWindowSDL::isPrimaryTextAvailable() { - if (ll_try_gtk_init()) - { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_SELECTION_PRIMARY); - return gtk_clipboard_wait_is_text_available(clipboard) ? - true : false; - } - return false; // failure + return SDL_HasPrimarySelectionText(); } -bool LLWindowSDL::pasteTextFromPrimary(LLWString &text) +bool LLWindowSDL::pasteTextFromPrimary(LLWString &dst) { - if (ll_try_gtk_init()) + if (isPrimaryTextAvailable()) { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_SELECTION_PRIMARY); - gchar * const data = gtk_clipboard_wait_for_text(clipboard); + char* data = SDL_GetPrimarySelectionText(); if (data) { - text = LLWString(utf8str_to_wstring(data)); - g_free(data); + dst = LLWString(utf8str_to_wstring(data)); + SDL_free(data); return true; } } - return false; // failure -} - -bool LLWindowSDL::copyTextToPrimary(const LLWString &text) -{ - if (ll_try_gtk_init()) - { - const std::string utf8 = wstring_to_utf8str(text); - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_SELECTION_PRIMARY); - gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); - return true; - } - return false; // failure -} - -#else - -bool LLWindowSDL::isClipboardTextAvailable() -{ - return false; // unsupported -} - -bool LLWindowSDL::pasteTextFromClipboard(LLWString &dst) -{ - return false; // unsupported -} - -bool LLWindowSDL::copyTextToClipboard(const LLWString &s) -{ - return false; // unsupported -} - -bool LLWindowSDL::isPrimaryTextAvailable() -{ - return false; // unsupported -} - -bool LLWindowSDL::pasteTextFromPrimary(LLWString &dst) -{ - return false; // unsupported + return false; } -bool LLWindowSDL::copyTextToPrimary(const LLWString &s) +bool LLWindowSDL::copyTextToPrimary(const LLWString& text) { - return false; // unsupported + const std::string utf8 = wstring_to_utf8str(text); + return SDL_SetPrimarySelectionText(utf8.c_str()); } -#endif // LL_GTK - LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions) { if (!mSupportedResolutions) @@ -1368,28 +985,21 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; mNumSupportedResolutions = 0; - SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN); - if ( (modes != NULL) && (modes != ((SDL_Rect **) -1)) ) - { - int count = 0; - while (*modes && count<MAX_NUM_RESOLUTIONS) // they're sorted biggest to smallest, so find end... - { - modes++; - count++; - } - - while (count--) - { - modes--; - SDL_Rect *r = *modes; - int w = r->w; - int h = r->h; + SDL_DisplayID display = SDL_GetPrimaryDisplay(); + int num_modes = 0; + SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(display, &num_modes); + num_modes = llclamp(num_modes, 0, MAX_NUM_RESOLUTIONS); + if (modes) { + for (int i = 0; i < num_modes; ++i) { + SDL_DisplayMode *mode = modes[i]; + 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-1].mWidth != w) && + (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) ) { mSupportedResolutions[mNumSupportedResolutions].mWidth = w; mSupportedResolutions[mNumSupportedResolutions].mHeight = h; @@ -1397,6 +1007,7 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso } } } + SDL_free(modes); } } @@ -1404,13 +1015,42 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso return mSupportedResolutions; } +//static +std::vector<std::string> LLWindowSDL::getDisplaysResolutionList() +{ + std::vector<std::string> ret; + if (gWindowImplementation) + { + S32 resolutionCount = 0; + LLWindowResolution* resolutionList = gWindowImplementation->getSupportedResolutions(resolutionCount); + if (resolutionList != nullptr) + { + for (S32 i = 0; i < resolutionCount; i++) + { + const LLWindowResolution& resolution = resolutionList[i]; + ret.push_back(std::to_string(resolution.mWidth) + "x" + std::to_string(resolution.mHeight)); + } + } + } + return ret; +} + + bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to) { if (!to) return false; - to->mX = from.mX; - to->mY = mWindow->h - from.mY - 1; + if (!mWindow) + return false; + + S32 height; + SDL_GetWindowSizeInPixels(mWindow, nullptr, &height); + + float pixel_scale = SDL_GetWindowPixelDensity(mWindow); + + to->mX = from.mX / pixel_scale; + to->mY = (height - from.mY - 1) / pixel_scale; return true; } @@ -1420,8 +1060,15 @@ bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) if (!to) return false; - to->mX = from.mX; - to->mY = mWindow->h - from.mY - 1; + if (!mWindow) + return false; + S32 height; + SDL_GetWindowSize(mWindow, nullptr, &height); + + float pixel_scale = SDL_GetWindowPixelDensity(mWindow); + + to->mX = from.mX * pixel_scale; + to->mY = (height - from.mY - 1) * pixel_scale; return true; } @@ -1434,7 +1081,7 @@ bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) // In the fullscreen case, window and screen coordinates are the same. to->mX = from.mX; to->mY = from.mY; - return (true); + return true; } bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) @@ -1445,29 +1092,26 @@ bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) // In the fullscreen case, window and screen coordinates are the same. to->mX = from.mX; to->mY = from.mY; - return (true); + return true; } bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) { LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + 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)); + return convertCoords(from, &window_coord) && convertCoords(window_coord, to); } - - - void LLWindowSDL::setupFailure(const std::string& text, const std::string& caption, U32 type) { - destroyContext(); + close(); OSMessageBox(text, caption, type); } @@ -1482,13 +1126,13 @@ bool LLWindowSDL::SDLReallyCaptureInput(bool capture) else mReallyCapturedCount = 0; - SDL_GrabMode wantmode, newmode; + bool wantGrab; if (mReallyCapturedCount <= 0) // uncapture { - wantmode = SDL_GRAB_OFF; + wantGrab = false; } else // capture { - wantmode = SDL_GRAB_ON; + wantGrab = true; } if (mReallyCapturedCount < 0) // yuck, imbalance. @@ -1497,64 +1141,32 @@ bool LLWindowSDL::SDLReallyCaptureInput(bool capture) LL_WARNS() << "ReallyCapture count was < 0" << LL_ENDL; } + bool newGrab = wantGrab; if (!mFullscreen) /* only bother if we're windowed anyway */ { -#if LL_X11 - if (mSDL_Display) + int result; + if (wantGrab) { - /* 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 (wantmode == SDL_GRAB_ON) - { - //LL_INFOS() << "X11 POINTER GRABBY" << LL_ENDL; - //newmode = SDL_WM_GrabInput(wantmode); - maybe_lock_display(); - result = XGrabPointer(mSDL_Display, mSDL_XWindowID, - True, 0, GrabModeAsync, - GrabModeAsync, - None, None, CurrentTime); - maybe_unlock_display(); - if (GrabSuccess == result) - newmode = SDL_GRAB_ON; - else - newmode = SDL_GRAB_OFF; - } else if (wantmode == SDL_GRAB_OFF) - { - //LL_INFOS() << "X11 POINTER UNGRABBY" << LL_ENDL; - newmode = SDL_GRAB_OFF; - //newmode = SDL_WM_GrabInput(SDL_GRAB_OFF); - - maybe_lock_display(); - XUngrabPointer(mSDL_Display, CurrentTime); - // Make sure the ungrab happens RIGHT NOW. - XSync(mSDL_Display, False); - maybe_unlock_display(); - } else - { - newmode = SDL_GRAB_QUERY; // neutral - } - } else // not actually running on X11, for some reason - newmode = wantmode; -#endif // LL_X11 - } else { - // pretend we got what we wanted, when really we don't care. - newmode = wantmode; + // LL_INFOS() << "X11 POINTER GRABBY" << LL_ENDL; + result = SDL_SetWindowMouseGrab(mWindow, true); + if (0 == result) + newGrab = true; + else + newGrab = false; + } + else + { + newGrab = false; + result = SDL_SetWindowMouseGrab(mWindow, false); + } } + // pretend we got what we wanted, when really we don't care. // return boolean success for whether we ended up in the desired state - return (capture && SDL_GRAB_ON==newmode) || - (!capture && SDL_GRAB_OFF==newmode); + return capture == newGrab; } -U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, bool gain) +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 @@ -1572,16 +1184,16 @@ U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, bool gain) 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; + 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) @@ -1595,371 +1207,265 @@ U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, bool gain) return mGrabbyKeyFlags; } - -void check_vm_bloat() +// virtual +void LLWindowSDL::processMiscNativeEvents() { -#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 + LLMutexLock osr_lock(&mOSRMutex); + for(SDL_Window* pWindow : mDeadOSRWindows) { - res = getdelim(&ptr, &dummy, ' ', fp); - if (-1 == res) - { - LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; - goto finally; - } - free(ptr); - ptr = NULL; + SDL_DestroyWindow(pWindow); } - // 23rd space-delimited entry is vsize - res = getdelim(&ptr, &dummy, ' ', fp); - llassert(ptr); - if (-1 == res) + mDeadOSRWindows.clear(); + } +} + +void LLWindowSDL::gatherInput() +{ + // This is for the case where SDL is not driving the main event loop + if(!gSDLMainHandled) + { + SDL_Event event; + + // Handle all outstanding SDL events + while (SDL_PollEvent(&event)) { - LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; - goto finally; + handleEvent(event); } - 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) + } + + updateCursor(); + + // This is a good time to stop flashing the icon if our mFlashTimer has + // expired. + if (mFlashing && mFlashTimer.hasExpired()) + { + SDL_FlashWindow(mWindow, SDL_FLASH_CANCEL); + mFlashing = false; + } +} + +SDL_AppResult LLWindowSDL::handleEvent(const SDL_Event& event) +{ + switch(event.type) + { + case SDL_EVENT_MOUSE_MOTION: { - LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; - goto finally; + LLCoordWindow winCoord(llfloor(event.motion.x), llfloor(event.motion.y)); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + mCallbacks->handleMouseMove(this, openGlCoord, gKeyboard->currentMask(true)); + break; } - 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) + case SDL_EVENT_MOUSE_WHEEL: { - if (this_vm_size > last_vm_size) + if(event.wheel.integer_y != 0) { - LL_WARNS() << "VM size grew by " << (this_vm_size - last_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + mCallbacks->handleScrollWheel(this, -event.wheel.integer_y); } - else + if (event.wheel.integer_x != 0) { - LL_INFOS() << "VM size shrank by " << (last_vm_size - this_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + mCallbacks->handleScrollHWheel(this, -event.wheel.integer_x); } + break; } - if (llabs(last_rss_size - this_rss_size) > - significant_rss_difference) + case SDL_EVENT_MOUSE_BUTTON_DOWN: { - if (this_rss_size > last_rss_size) + LLCoordWindow winCoord(llfloor(event.button.x), llfloor(event.button.y)); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + MASK mask = gKeyboard->currentMask(true); + + if (event.button.button == SDL_BUTTON_LEFT) // left + { + if (event.button.clicks == 2) + mCallbacks->handleDoubleClick(this, openGlCoord, mask); + else + mCallbacks->handleMouseDown(this, openGlCoord, mask); + } + else if (event.button.button == SDL_BUTTON_RIGHT) { - LL_WARNS() << "RSS size grew by " << (this_rss_size - last_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + mCallbacks->handleRightMouseDown(this, openGlCoord, mask); + } + else if (event.button.button == SDL_BUTTON_MIDDLE) // middle + { + mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); } else { - LL_INFOS() << "RSS size shrank by " << (last_rss_size - this_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + mCallbacks->handleOtherMouseDown(this, openGlCoord, mask, event.button.button); } - } - - last_rss_size = this_rss_size; - last_vm_size = this_vm_size; -finally: - if (NULL != ptr) - { - free(ptr); - ptr = NULL; + break; } - fclose(fp); - } -#endif // LL_LINUX -} + case SDL_EVENT_MOUSE_BUTTON_UP: + { + LLCoordWindow winCoord(llfloor(event.button.x), llfloor(event.button.y)); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + MASK mask = gKeyboard->currentMask(true); -// virtual -void LLWindowSDL::processMiscNativeEvents() -{ -#if LL_GTK - // Pump GTK events to avoid starvation for: - // * DBUS servicing - // * Anything else which quietly hooks into the default glib/GTK loop - if (ll_try_gtk_init()) - { - // Yuck, Mozilla's GTK callbacks play with the locale - push/pop - // the locale to protect it, as exotic/non-C locales - // causes our code lots of general critical weirdness - // and crashness. (SL-35450) - static std::string saved_locale; - saved_locale = ll_safe_string(setlocale(LC_ALL, NULL)); + 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); + } + else + { + mCallbacks->handleOtherMouseUp(this, openGlCoord, mask, event.button.button); + } - // 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 { - // Always do at least one non-blocking pump - gtk_main_iteration_do(false); - } while (gtk_events_pending() && - !pump_timer.hasExpired()); + break; + } - setlocale(LC_ALL, saved_locale.c_str() ); - } -#endif // LL_GTK + case SDL_EVENT_KEY_DOWN: + { + mKeyVirtualKey = event.key.key; + mKeyModifiers = event.key.mod; - // hack - doesn't belong here - but this is just for debugging - if (getenv("LL_DEBUG_BLOAT")) - { - check_vm_bloat(); - } -} + if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) + { + mKeyVirtualKey = SDLK_RETURN; + } -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; + gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers); - // Handle all outstanding SDL events - while (SDL_PollEvent(&event)) - { - switch (event.type) - { - case SDL_MOUSEMOTION: + if (mKeyVirtualKey == SDLK_RETURN) { - LLCoordWindow winCoord(event.button.x, event.button.y); - LLCoordGL openGlCoord; - convertCoords(winCoord, &openGlCoord); - MASK mask = gKeyboard->currentMask(true); - mCallbacks->handleMouseMove(this, openGlCoord, mask); - break; + // fix return key not working when capslock, scrolllock or numlock are enabled + mKeyModifiers &= (~(SDL_KMOD_NUM | SDL_KMOD_CAPS | SDL_KMOD_MODE | SDL_KMOD_SCROLL)); + mCallbacks->handleUnicodeChar(mKeyVirtualKey, gKeyboard->currentMask(false)); } - case SDL_KEYDOWN: - mKeyScanCode = event.key.keysym.scancode; - mKeyVirtualKey = event.key.keysym.unicode; - mKeyModifiers = event.key.keysym.mod; - - gKeyboard->handleKeyDown(event.key.keysym.sym, event.key.keysym.mod); // part of the fix for SL-13243 - if (SDLCheckGrabbyKeys(event.key.keysym.sym, true) != 0) + if (SDLCheckGrabbyKeys(mKeyVirtualKey, true) != 0) SDLReallyCaptureInput(true); + break; + } + + case SDL_EVENT_KEY_UP: + { + mKeyVirtualKey = event.key.key; + mKeyModifiers = event.key.mod; - if (event.key.keysym.unicode) + if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) { - handleUnicodeUTF16(event.key.keysym.unicode, - gKeyboard->currentMask(false)); + mKeyVirtualKey = SDLK_RETURN; } - break; - case SDL_KEYUP: - mKeyScanCode = event.key.keysym.scancode; - mKeyVirtualKey = event.key.keysym.unicode; - mKeyModifiers = event.key.keysym.mod; - - if (SDLCheckGrabbyKeys(event.key.keysym.sym, false) == 0) + gKeyboard->handleKeyUp(mKeyVirtualKey, mKeyModifiers); + if (SDLCheckGrabbyKeys(mKeyVirtualKey, false) == 0) SDLReallyCaptureInput(false); // part of the fix for SL-13243 - - gKeyboard->handleKeyUp(event.key.keysym.sym, event.key.keysym.mod); 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: + case SDL_EVENT_TEXT_INPUT: + { + auto string = utf8str_to_wstring(event.text.text); + MASK current_mask = gKeyboard->currentMask(false); + for (auto key : string) { - 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; + mKeyVirtualKey = key; + mCallbacks->handleUnicodeChar(key, current_mask); } + break; + } - case SDL_VIDEOEXPOSE: // VIDEOEXPOSE doesn't specify the damage, but hey, it's OpenGL...repaint the whole thing! - mCallbacks->handlePaint(this, 0, 0, mWindow->w, mWindow->h); - break; - - case SDL_VIDEORESIZE: // *FIX: handle this? - { - LL_INFOS() << "Handling a resize event: " << event.resize.w << - "x" << event.resize.h << LL_ENDL; - - S32 width = llmax(event.resize.w, (S32)mMinWindowWidth); - S32 height = llmax(event.resize.h, (S32)mMinWindowHeight); - - // *FIX: I'm not sure this is necessary! - mWindow = SDL_SetVideoMode(width, height, 32, mSDLFlags); - if (!mWindow) + case SDL_EVENT_WINDOW_EXPOSED: { - // *FIX: More informative dialog? - LL_INFOS() << "Could not recreate context after resize! Quitting..." << LL_ENDL; - if(mCallbacks->handleCloseRequest(this, false)) - { - // Get the app to initiate cleanup. - mCallbacks->handleQuit(this); - // The app is responsible for calling destroyWindow when done with GL - } - break; + mCallbacks->handlePaint(this, 0, 0, 0, 0); + break; } - mCallbacks->handleResize(this, width, height); - break; - } - case SDL_ACTIVEEVENT: - if (event.active.state & SDL_APPINPUTFOCUS) - { - // Note that for SDL (particularly on X11), keyboard - // and mouse focus are independent things. Here we are - // tracking keyboard focus state changes. - - // 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]. - if (event.active.gain != mHaveInputFocus) - { - mHaveInputFocus = !!event.active.gain; + case SDL_EVENT_WINDOW_RESIZED: + { + LL_INFOS() << "Handling a resize event: " << event.window.data1 << "x" << event.window.data2 << LL_ENDL; + F32 pixel_density = SDL_GetWindowPixelDensity(mWindow); + S32 width = llmax(event.window.data1, (S32)mMinWindowWidth) * pixel_density; + S32 height = llmax(event.window.data2, (S32)mMinWindowHeight) * pixel_density; - if (mHaveInputFocus) - mCallbacks->handleFocus(this); - else - mCallbacks->handleFocusLost(this); - } - } - if (event.active.state & SDL_APPACTIVE) - { - // Change in iconification/minimization state. - if ((!event.active.gain) != mIsMinimized) + mCallbacks->handleResize(this, width, height); + break; + } + case SDL_EVENT_WINDOW_MOUSE_ENTER: + break; + case SDL_EVENT_WINDOW_MOUSE_LEAVE: + mCallbacks->handleMouseLeave(this); + break; + case SDL_EVENT_WINDOW_FOCUS_GAINED: + //SDL_SetWindowKeyboardGrab(mWindow, true); + mCallbacks->handleFocus(this); + break; + case SDL_EVENT_WINDOW_FOCUS_LOST: + mCallbacks->handleFocusLost(this); + //SDL_SetWindowKeyboardGrab(mWindow, false); + break; + case SDL_EVENT_WINDOW_RESTORED: + mCallbacks->handleActivate(this, true); + break; + case SDL_EVENT_WINDOW_MAXIMIZED: + mCallbacks->handleActivate(this, true); + break; + case SDL_EVENT_WINDOW_MINIMIZED: + mCallbacks->handleActivate(this, false); + break; + case SDL_EVENT_WINDOW_DISPLAY_CHANGED: + { + // Update refresh rate when changing monitors + const SDL_DisplayMode* displayMode = SDL_GetCurrentDisplayMode(event.window.data1); + if(displayMode) { - mIsMinimized = (!event.active.gain); - - mCallbacks->handleActivate(this, !mIsMinimized); - LL_INFOS() << "SDL deiconification state switched to " << bool(event.active.gain) << LL_ENDL; + mRefreshRate = ll_round(displayMode->refresh_rate); + mNativeAspectRatio = ((F32)displayMode->w) / ((F32)displayMode->h); } - else + mCallbacks->handleDisplayChanged(); + break; + } + case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: + { + S32 w, h = 0; + SDL_GetWindowSizeInPixels(mWindow, &w, &h); + mCallbacks->handleDPIChanged(this, getSystemUISize(), w, h); + break; + } + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: + { + if(mCallbacks->handleCloseRequest(this, true)) { - LL_INFOS() << "Ignored bogus redundant SDL deiconification state switch to " << bool(event.active.gain) << LL_ENDL; + // Get the app to initiate cleanup. + mCallbacks->handleQuit(this); + // The app is responsible for calling destroyWindow when done with GL } - } - break; - - case SDL_QUIT: - if(mCallbacks->handleCloseRequest(this, true)) - { - // 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; + break; } + default: + break; } - updateCursor(); + return SDL_APP_CONTINUE; +} -#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_AppResult LLWindowSDL::handleEvents(const SDL_Event& event) +{ + if(!gWindowImplementation) return SDL_APP_CONTINUE; + + return gWindowImplementation->handleEvent(event); } static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty) { - SDL_Cursor *sdlcursor = NULL; + SDL_Cursor *sdlcursor = nullptr; SDL_Surface *bmpsurface; // Load cursor pixel data from BMP file @@ -1968,21 +1474,32 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty { 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)); + << bmpsurface->w << "x" << bmpsurface->h << LL_ENDL; + SDL_PixelFormat pix_format = SDL_GetPixelFormatForMasks(32, + SDL_Swap32LE(0xFFU), + SDL_Swap32LE(0xFF00U), + SDL_Swap32LE(0xFF0000U), + SDL_Swap32LE(0xFF000000U)); + if (pix_format == SDL_PIXELFORMAT_UNKNOWN) + { + return nullptr; + } + + const SDL_PixelFormatDetails* pix_format_details = SDL_GetPixelFormatDetails(pix_format); + if(!pix_format_details) + { + return nullptr; + } + + cursurface = SDL_CreateSurface(bmpsurface->w, + bmpsurface->h, + pix_format); + SDL_FillSurfaceRect(cursurface, nullptr, SDL_Swap32LE(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)) + if (SDL_BlitSurface(bmpsurface, nullptr, + cursurface, nullptr)) { // n.b. we already checked that width is a multiple of 8. const int bitmap_bytes = (cursurface->w * cursurface->h) / 8; @@ -1997,33 +1514,33 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty for (i=0; i<cursurface->h; ++i) { for (j=0; j<cursurface->w; ++j) { U8 *pixelp = - ((U8*)cursurface->pixels) - + cursurface->pitch * i - + j*cursurface->format->BytesPerPixel; + ((U8*)cursurface->pixels) + + cursurface->pitch * i + + j*pix_format_details->bytes_per_pixel; U8 srcred = pixelp[0]; U8 srcgreen = pixelp[1]; U8 srcblue = pixelp[2]; bool mask_bit = (srcred != 200) - || (srcgreen != 200) - || (srcblue != 200); + || (srcgreen != 200) + || (srcblue != 200); bool data_bit = mask_bit && (srcgreen <= 80);//not 0x80 unsigned char bit_offset = (cursurface->w/8) * i - + j/8; + + 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); + (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); + SDL_DestroySurface(cursurface); + SDL_DestroySurface(bmpsurface); } else { LL_WARNS() << "CURSOR LOAD FAILURE " << filename << LL_ENDL; } @@ -2033,12 +1550,6 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty 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) @@ -2050,37 +1561,40 @@ void LLWindowSDL::updateCursor() sdlcursor = mSDLCursors[UI_CURSOR_ARROW]; if (sdlcursor) SDL_SetCursor(sdlcursor); - } else { + + mCurrentCursor = mNextCursor; + } + else + { LL_WARNS() << "Tried to set invalid cursor number " << mNextCursor << LL_ENDL; } - mCurrentCursor = mNextCursor; } } void LLWindowSDL::initCursors() { - int i; // Blank the cursor pointer array for those we may miss. - for (i=0; i<UI_CURSOR_COUNT; ++i) + for (int i=0; i<UI_CURSOR_COUNT; ++i) { - mSDLCursors[i] = NULL; + mSDLCursors[i] = nullptr; } + // Pre-make an SDL cursor for each of the known cursor types. // We hardcode the hotspots - to avoid that we'd have to write // a .cur file loader. // NOTE: SDL doesn't load RLE-compressed BMP files. - mSDLCursors[UI_CURSOR_ARROW] = makeSDLCursorFromBMP("llarrow.BMP",0,0); - mSDLCursors[UI_CURSOR_WAIT] = makeSDLCursorFromBMP("wait.BMP",12,15); - mSDLCursors[UI_CURSOR_HAND] = makeSDLCursorFromBMP("hand.BMP",7,10); - mSDLCursors[UI_CURSOR_IBEAM] = makeSDLCursorFromBMP("ibeam.BMP",15,16); - mSDLCursors[UI_CURSOR_CROSS] = makeSDLCursorFromBMP("cross.BMP",16,14); - mSDLCursors[UI_CURSOR_SIZENWSE] = makeSDLCursorFromBMP("sizenwse.BMP",14,17); - mSDLCursors[UI_CURSOR_SIZENESW] = makeSDLCursorFromBMP("sizenesw.BMP",17,17); - mSDLCursors[UI_CURSOR_SIZEWE] = makeSDLCursorFromBMP("sizewe.BMP",16,14); - mSDLCursors[UI_CURSOR_SIZENS] = makeSDLCursorFromBMP("sizens.BMP",17,16); - mSDLCursors[UI_CURSOR_SIZEALL] = makeSDLCursorFromBMP("sizeall.BMP", 17, 17); - mSDLCursors[UI_CURSOR_NO] = makeSDLCursorFromBMP("llno.BMP",8,8); - mSDLCursors[UI_CURSOR_WORKING] = makeSDLCursorFromBMP("working.BMP",12,15); + mSDLCursors[UI_CURSOR_ARROW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT); + mSDLCursors[UI_CURSOR_WAIT] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); + mSDLCursors[UI_CURSOR_HAND] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER); + mSDLCursors[UI_CURSOR_IBEAM] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_TEXT); + mSDLCursors[UI_CURSOR_CROSS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR); + mSDLCursors[UI_CURSOR_SIZENWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NWSE_RESIZE); + mSDLCursors[UI_CURSOR_SIZENESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NESW_RESIZE); + mSDLCursors[UI_CURSOR_SIZEWE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_EW_RESIZE); + mSDLCursors[UI_CURSOR_SIZENS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NS_RESIZE); + mSDLCursors[UI_CURSOR_SIZEALL] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE); + mSDLCursors[UI_CURSOR_NO] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED); + mSDLCursors[UI_CURSOR_WORKING] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_PROGRESS); mSDLCursors[UI_CURSOR_TOOLGRAB] = makeSDLCursorFromBMP("lltoolgrab.BMP",2,13); mSDLCursors[UI_CURSOR_TOOLLAND] = makeSDLCursorFromBMP("lltoolland.BMP",1,6); mSDLCursors[UI_CURSOR_TOOLFOCUS] = makeSDLCursorFromBMP("lltoolfocus.BMP",8,5); @@ -2113,32 +1627,28 @@ void LLWindowSDL::initCursors() 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<UI_CURSOR_COUNT; ++i) + for (int i=0; i<UI_CURSOR_COUNT; ++i) { if (mSDLCursors[i]) { - SDL_FreeCursor(mSDLCursors[i]); - mSDLCursors[i] = NULL; + SDL_DestroyCursor(mSDLCursors[i]); + mSDLCursors[i] = nullptr; } } - } else { + } + else + { // SDL doesn't refcount cursors, so if the window has // already been destroyed then the cursors have gone with it. LL_INFOS() << "Skipping quitCursors: mWindow already gone." << LL_ENDL; - for (i=0; i<UI_CURSOR_COUNT; ++i) - mSDLCursors[i] = NULL; + for (int i=0; i<UI_CURSOR_COUNT; ++i) + mSDLCursors[i] = nullptr; } } @@ -2167,7 +1677,7 @@ void LLWindowSDL::hideCursor() // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; mCursorHidden = true; mHideCursorPermanent = true; - SDL_ShowCursor(0); + SDL_HideCursor(); } else { @@ -2182,7 +1692,7 @@ void LLWindowSDL::showCursor() // LL_INFOS() << "showCursor: showing" << LL_ENDL; mCursorHidden = false; mHideCursorPermanent = false; - SDL_ShowCursor(1); + SDL_ShowCursor(); } else { @@ -2207,8 +1717,6 @@ void LLWindowSDL::hideCursorUntilMouseMove() } } - - // // LLSplashScreenSDL - I don't think we'll bother to implement this; it's // fairly obsolete at this point. @@ -2233,133 +1741,62 @@ void LLSplashScreenSDL::hideImpl() { } - - -#if LL_GTK -static void response_callback (GtkDialog *dialog, - gint arg1, - gpointer user_data) -{ - gint *response = (gint*)user_data; - *response = arg1; - gtk_widget_destroy(GTK_WIDGET(dialog)); - gtk_main_quit(); -} - S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) { - S32 rtn = OSBTN_CANCEL; - - if(gWindowImplementation != NULL) - gWindowImplementation->beforeDialog(); + SDL_MessageBoxData oData = { SDL_MESSAGEBOX_INFORMATION, nullptr, caption.c_str(), text.c_str(), 0, nullptr, nullptr }; + SDL_MessageBoxButtonData btnOk[] = {{SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, OSBTN_OK, "OK" }}; + SDL_MessageBoxButtonData btnOkCancel [] = {{SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, OSBTN_OK, "OK" }, {SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, OSBTN_CANCEL, "Cancel"} }; + SDL_MessageBoxButtonData btnYesNo[] = { {SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, OSBTN_YES, "Yes" }, {SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, OSBTN_NO, "No"} }; - if (LLWindowSDL::ll_try_gtk_init()) + switch (type) { - GtkWidget *win = NULL; - - LL_INFOS() << "Creating a dialog because we're in windowed mode and GTK is happy." << LL_ENDL; - - GtkDialogFlags flags = GTK_DIALOG_MODAL; - GtkMessageType messagetype; - GtkButtonsType buttons; - switch (type) - { default: case OSMB_OK: - messagetype = GTK_MESSAGE_WARNING; - buttons = GTK_BUTTONS_OK; + oData.flags = SDL_MESSAGEBOX_WARNING; + oData.buttons = btnOk; + oData.numbuttons = 1; break; case OSMB_OKCANCEL: - messagetype = GTK_MESSAGE_QUESTION; - buttons = GTK_BUTTONS_OK_CANCEL; + oData.flags = SDL_MESSAGEBOX_INFORMATION; + oData.buttons = btnOkCancel; + oData.numbuttons = 2; break; case OSMB_YESNO: - messagetype = GTK_MESSAGE_QUESTION; - buttons = GTK_BUTTONS_YES_NO; + oData.flags = SDL_MESSAGEBOX_INFORMATION; + oData.buttons = btnYesNo; + oData.numbuttons = 2; break; - } - win = gtk_message_dialog_new(NULL, flags, messagetype, buttons, "%s", - text.c_str()); - -# if LL_X11 - // Make GTK tell the window manager to associate this - // dialog with our non-GTK SDL window, which should try - // to keep it on top etc. - if (gWindowImplementation && - gWindowImplementation->mSDL_XWindowID != None) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(gWindowImplementation->mSDL_XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } -# endif //LL_X11 - - gtk_window_set_position(GTK_WINDOW(win), - GTK_WIN_POS_CENTER_ON_PARENT); - - gtk_window_set_type_hint(GTK_WINDOW(win), - GDK_WINDOW_TYPE_HINT_DIALOG); - - if (!caption.empty()) - gtk_window_set_title(GTK_WINDOW(win), caption.c_str()); - - gint response = GTK_RESPONSE_NONE; - g_signal_connect (win, - "response", - G_CALLBACK (response_callback), - &response); + } - // we should be able to use a gtk_dialog_run(), but it's - // apparently not written to exist in a world without a higher - // gtk_main(), so we manage its signal/destruction outselves. - gtk_widget_show_all (win); - gtk_main(); + if(gWindowImplementation != nullptr) + gWindowImplementation->beforeDialog(); - //LL_INFOS() << "response: " << response << LL_ENDL; - switch (response) - { - case GTK_RESPONSE_OK: rtn = OSBTN_OK; break; - case GTK_RESPONSE_YES: rtn = OSBTN_YES; break; - case GTK_RESPONSE_NO: rtn = OSBTN_NO; break; - case GTK_RESPONSE_APPLY: rtn = OSBTN_OK; break; - case GTK_RESPONSE_NONE: - case GTK_RESPONSE_CANCEL: - case GTK_RESPONSE_CLOSE: - case GTK_RESPONSE_DELETE_EVENT: - default: rtn = OSBTN_CANCEL; - } - } - else + int btn{0}; + if(SDL_ShowMessageBox( &oData, &btn )) { - LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; - LL_INFOS() << "Skipping dialog because we're in fullscreen mode or GTK is not happy." << LL_ENDL; - rtn = OSBTN_OK; + if(gWindowImplementation != nullptr) + gWindowImplementation->afterDialog(); + return btn; } - if(gWindowImplementation != NULL) + if(gWindowImplementation != nullptr) gWindowImplementation->afterDialog(); - return rtn; + return OSBTN_CANCEL; } -static void color_changed_callback(GtkWidget *widget, - gpointer user_data) +bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) { - GtkColorSelection *colorsel = GTK_COLOR_SELECTION(widget); - GdkColor *colorp = (GdkColor*)user_data; - - gtk_color_selection_get_current_color(colorsel, colorp); + return false; } - /* Make the raw keyboard data available - used to poke through to LLQtWebKit so that Qt/Webkit has access to the virtual keycodes etc. that it needs */ LLSD LLWindowSDL::getNativeKeyData() { - LLSD result = LLSD::emptyMap(); + LLSD result = LLSD::emptyMap(); U32 modifiers = 0; // pretend-native modifiers... oh what a tangled web we weave! @@ -2367,140 +1804,21 @@ LLSD LLWindowSDL::getNativeKeyData() // what a plugin under GDK under Qt under SL under SDL under X11 considers // a 'native' modifier mask. this has been sort of reverse-engineered... they *appear* // to match GDK consts, but that may be co-incidence. - modifiers |= (mKeyModifiers & KMOD_LSHIFT) ? 0x0001 : 0; - modifiers |= (mKeyModifiers & KMOD_RSHIFT) ? 0x0001 : 0;// munge these into the same shift - modifiers |= (mKeyModifiers & KMOD_CAPS) ? 0x0002 : 0; - modifiers |= (mKeyModifiers & KMOD_LCTRL) ? 0x0004 : 0; - modifiers |= (mKeyModifiers & KMOD_RCTRL) ? 0x0004 : 0;// munge these into the same ctrl - modifiers |= (mKeyModifiers & KMOD_LALT) ? 0x0008 : 0;// untested - modifiers |= (mKeyModifiers & KMOD_RALT) ? 0x0008 : 0;// untested + modifiers |= (mKeyModifiers & SDL_KMOD_LSHIFT) ? 0x0001 : 0; + modifiers |= (mKeyModifiers & SDL_KMOD_RSHIFT) ? 0x0001 : 0;// munge these into the same shift + modifiers |= (mKeyModifiers & SDL_KMOD_CAPS) ? 0x0002 : 0; + modifiers |= (mKeyModifiers & SDL_KMOD_LCTRL) ? 0x0004 : 0; + modifiers |= (mKeyModifiers & SDL_KMOD_RCTRL) ? 0x0004 : 0;// munge these into the same ctrl + modifiers |= (mKeyModifiers & SDL_KMOD_LALT) ? 0x0008 : 0;// untested + modifiers |= (mKeyModifiers & SDL_KMOD_RALT) ? 0x0008 : 0;// untested // *todo: test ALTs - I don't have a case for testing these. Do you? // *todo: NUM? - I don't care enough right now (and it's not a GDK modifier). - result["scan_code"] = (S32)mKeyScanCode; - result["virtual_key"] = (S32)mKeyVirtualKey; + result["virtual_key"] = (S32)mKeyVirtualKey; + result["virtual_key_win"] = (S32)LLKeyboardSDL::mapSDLtoWin( mKeyVirtualKey ); result["modifiers"] = (S32)modifiers; - - return result; -} - - -bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ - bool rtn = false; - - beforeDialog(); - - if (ll_try_gtk_init()) - { - GtkWidget *win = NULL; - - win = gtk_color_selection_dialog_new(NULL); - -# if LL_X11 - // Get GTK to tell the window manager to associate this - // dialog with our non-GTK SDL window, which should try - // to keep it on top etc. - if (mSDL_XWindowID != None) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(mSDL_XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } -# endif //LL_X11 - - GtkColorSelection *colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG(win)->colorsel); - - GdkColor color, orig_color; - orig_color.pixel = 0; - orig_color.red = guint16(65535 * *r); - orig_color.green= guint16(65535 * *g); - orig_color.blue = guint16(65535 * *b); - color = orig_color; - - gtk_color_selection_set_previous_color (colorsel, &color); - gtk_color_selection_set_current_color (colorsel, &color); - gtk_color_selection_set_has_palette (colorsel, true); - gtk_color_selection_set_has_opacity_control(colorsel, false); - - gint response = GTK_RESPONSE_NONE; - g_signal_connect (win, - "response", - G_CALLBACK (response_callback), - &response); - - g_signal_connect (G_OBJECT (colorsel), "color_changed", - G_CALLBACK (color_changed_callback), - &color); - - gtk_window_set_modal(GTK_WINDOW(win), true); - gtk_widget_show_all(win); - // hide the help button - we don't service it. - gtk_widget_hide(GTK_COLOR_SELECTION_DIALOG(win)->help_button); - gtk_main(); - - if (response == GTK_RESPONSE_OK && - (orig_color.red != color.red - || orig_color.green != color.green - || orig_color.blue != color.blue) ) - { - *r = color.red / 65535.0f; - *g = color.green / 65535.0f; - *b = color.blue / 65535.0f; - rtn = true; - } - } - - afterDialog(); - - return rtn; -} -#else -S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) -{ - LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; - return 0; -} - -bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ - return (false); -} -#endif // LL_GTK - -#if LL_LINUX -// extracted from spawnWebBrowser for clarity and to eliminate -// compiler confusion regarding close(int fd) vs. LLWindow::close() -void exec_cmd(const std::string& cmd, const std::string& arg) -{ - char* const argv[] = {(char*)cmd.c_str(), (char*)arg.c_str(), NULL}; - fflush(NULL); - pid_t pid = fork(); - if (pid == 0) - { // child - // disconnect from stdin/stdout/stderr, or child will - // keep our output pipe undesirably alive if it outlives us. - close(0); - close(1); - close(2); - // 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; - } - } + return result; } -#endif // Open a URL with the user's default web browser. // Must begin with protocol identifier. @@ -2525,56 +1843,26 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) LL_INFOS() << "spawn_web_browser: " << escaped_url << LL_ENDL; -#if LL_LINUX -# if LL_X11 - if (mSDL_Display) + if (!SDL_OpenURL(escaped_url.c_str())) { - maybe_lock_display(); - // Just in case - before forking. - XSync(mSDL_Display, False); - maybe_unlock_display(); + LL_WARNS() << "spawn_web_browser failed with error: " << SDL_GetError() << LL_ENDL; } -# 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::getPlatformWindow() +void* LLWindowSDL::getPlatformWindow() { -#if LL_GTK && LL_LLMOZLIB_ENABLED - if (LLWindowSDL::ll_try_gtk_init()) + void* ret = nullptr; + if (mWindow) { - maybe_lock_display(); - - GtkWidget *owin = gtk_window_new(GTK_WINDOW_POPUP); - // Why a layout widget? A MozContainer would be ideal, but - // it involves exposing Mozilla headers to mozlib-using apps. - // A layout widget with a GtkWindow parent has the desired - // properties of being plain GTK, having a window, and being - // derived from a GtkContainer. - GtkWidget *rtnw = gtk_layout_new(NULL, NULL); - gtk_container_add(GTK_CONTAINER(owin), rtnw); - gtk_widget_realize(rtnw); - GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(rtnw), GTK_NO_WINDOW); - - maybe_unlock_display(); - - return rtnw; +#if LL_WINDOWS + ret = SDL_GetPointerProperty(SDL_GetWindowProperties(mWindow), SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr); +#elif LL_DARWIN + ret = SDL_GetPointerProperty(SDL_GetWindowProperties(mWindow), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr); +#endif } -#endif // LL_GTK && LL_LLMOZLIB_ENABLED - // Unixoid mozilla really needs GTK. - return NULL; + return ret; } void LLWindowSDL::bringToFront() @@ -2582,20 +1870,17 @@ 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) + if (mWindow && !mFullscreen) { - maybe_lock_display(); - XRaiseWindow(mSDL_Display, mSDL_XWindowID); - XSync(mSDL_Display, False); - maybe_unlock_display(); + SDL_RaiseWindow(mWindow); } -#endif // LL_X11 } //static std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() { + std::vector<std::string> rtns; +#if LL_LINUX // 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"); @@ -2612,9 +1897,9 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() // 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<std::string> rtns; - FcFontSet *fs = NULL; - FcPattern *sortpat = NULL; + + FcFontSet *fs = nullptr; + FcPattern *sortpat = nullptr; LL_INFOS() << "Getting system font list from FontConfig..." << LL_ENDL; @@ -2623,7 +1908,7 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() // 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_Locale *locale = nullptr; FL_Success success = FL_FindLocale(&locale, FL_MESSAGES); if (success != 0) { @@ -2634,10 +1919,10 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() LL_INFOS("AppInit") << "Variant " << locale->variant << LL_ENDL; LL_INFOS() << "Preferring fonts of language: " - << locale->lang - << LL_ENDL; + << locale->lang + << LL_ENDL; sort_order = "lang=" + std::string(locale->lang) + ":" - + sort_order; + + sort_order; } } FL_FreeLocale(&locale); @@ -2654,8 +1939,7 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() { // Sort the list of system fonts from most-to-least-desirable. FcResult result; - fs = FcFontSort(NULL, sortpat, elide_unicode_coverage, - NULL, &result); + fs = FcFontSort(nullptr, sortpat, elide_unicode_coverage, nullptr, &result); FcPatternDestroy(sortpat); } @@ -2668,10 +1952,7 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() for (int i=0; i<fs->nfont; ++i) { FcChar8 *filename; - if (FcResultMatch == FcPatternGetString(fs->fonts[i], - FC_FILE, 0, - &filename) - && 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) @@ -2682,16 +1963,101 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() } LL_DEBUGS() << "Using font list: " << LL_ENDL; - for (std::vector<std::string>::iterator it = rtns.begin(); - it != rtns.end(); - ++it) + for (auto 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); +#endif return rtns; } -#endif // LL_SDL +void LLWindowSDL::setLanguageTextInput(const LLCoordGL& position) +{ + LLCoordWindow win_pos; + convertCoords( position, &win_pos ); + + SDL_Rect r; + r.x = win_pos.mX; + r.y = win_pos.mY; + r.w = 500; + r.h = 16; + + SDL_SetTextInputArea(mWindow, &r, 0); +} + +F32 LLWindowSDL::getSystemUISize() +{ + if(mWindow) + { + F32 scale = SDL_GetWindowDisplayScale(mWindow); + if (scale > 0.0f) + { + return scale; + } + } + return 1.f; +} + +#if LL_DARWIN +// static +U64 LLWindowSDL::getVramSize() +{ + CGLRendererInfoObj info = 0; + GLint vram_megabytes = 0; + int num_renderers = 0; + CGLError the_err = CGLQueryRendererInfo (CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay), &info, &num_renderers); + if(0 == the_err) + { + // The name, uses, and other platform definitions of gGLManager.mVRAM suggest that this is supposed to be total vram in MB, + // rather than, say, just the texture memory. The two exceptions are: + // 1. LLAppViewer::getViewerInfo() puts the value in a field labeled "TEXTURE_MEMORY" + // 2. For years, this present function used kCGLRPTextureMemoryMegabytes + // Now we use kCGLRPVideoMemoryMegabytes to bring it in line with everything else (except thatone label). + CGLDescribeRenderer (info, 0, kCGLRPVideoMemoryMegabytes, &vram_megabytes); + CGLDestroyRendererInfo (info); + } + else + { + vram_megabytes = 256; + } + + return (U64)vram_megabytes; // return value is in megabytes. +} + +//static +void LLWindowSDL::setUseMultGL(bool use_mult_gl) +{ + bool was_enabled = sUseMultGL; + + sUseMultGL = use_mult_gl; + + if (gGLManager.mInited) + { + CGLContextObj ctx = CGLGetCurrentContext(); + //enable multi-threaded OpenGL (whether or not sUseMultGL actually changed) + if (sUseMultGL) + { + CGLError cgl_err = CGLEnable( ctx, kCGLCEMPEngine); + if (cgl_err != kCGLNoError ) + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; + sUseMultGL = false; + } + else + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; + } + } + else if (was_enabled) + { + CGLDisable( ctx, kCGLCEMPEngine); + LL_INFOS("GLInit") << "Multi-threaded OpenGL disabled." << LL_ENDL; + } + } +} +#endif + diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index 521d52df30..4d4a7a5f65 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -31,142 +31,163 @@ #include "llwindow.h" #include "lltimer.h" +#include "llmutex.h" -#include "SDL/SDL.h" -#include "SDL/SDL_endian.h" +#include "SDL3/SDL.h" +#include "SDL3/SDL_endian.h" -#if LL_X11 -// get X11-specific headers for use in low-level stuff like copy-and-paste support -#include "SDL/SDL_syswm.h" +#ifdef LL_WAYLAND +#include <wayland-client-protocol.h> #endif -// AssertMacros.h does bad things. -#include "fix_macros.h" -#undef verify -#undef require +#if LL_X11 +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#endif +class LLPreeditor; -class LLWindowSDL : public LLWindow +class LLWindowSDL final : 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*/ bool isWrapMouse() const override { return true; } - /*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); + void show() override; + void hide() override; + void restore() override; + + void close() override; + + bool getVisible() override; + + bool getMinimized() override; + + bool getMaximized() override; + + bool maximize() override; + void minimize() override; + + bool getPosition(LLCoordScreen *position) override; + + bool getSize(LLCoordScreen *size) override; + bool getSize(LLCoordWindow *size) override; + + bool setPosition(LLCoordScreen position) override; + + bool setSizeImpl(LLCoordScreen size) override; + bool setSizeImpl(LLCoordWindow size) override; + + bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, + const LLCoordScreen *const posp = NULL) override; + + bool setCursorPosition(LLCoordWindow position) override; - /*virtual*/ bool isClipboardTextAvailable(); - /*virtual*/ bool pasteTextFromClipboard(LLWString &dst); - /*virtual*/ bool copyTextToClipboard(const LLWString & src); + bool getCursorPosition(LLCoordWindow *position) override; + bool isWrapMouse() const override { return true; } + void showCursor() override; + void hideCursor() override; + bool isCursorHidden() override; - /*virtual*/ bool isPrimaryTextAvailable(); - /*virtual*/ bool pasteTextFromPrimary(LLWString &dst); - /*virtual*/ bool copyTextToPrimary(const LLWString & src); + void showCursorFromMouseMove() override; + void hideCursorUntilMouseMove() override; - /*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() {}; + void updateCursor() override; - /*virtual*/ void delayInputProcessing() { }; + void captureMouse() override; + void releaseMouse() override; + + void setMouseClipping(bool b) override; + + void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true) override; + + bool isClipboardTextAvailable() override; + bool pasteTextFromClipboard(LLWString &dst) override; + bool copyTextToClipboard(const LLWString &src) override; + + bool isPrimaryTextAvailable() override; + bool pasteTextFromPrimary(LLWString &dst) override; + bool copyTextToPrimary(const LLWString &src) override; + + void flashIcon(F32 seconds) override; + void maybeStopFlashIcon(); + + F32 getGamma() override; + bool setGamma(const F32 gamma) override; // Set the gamma + bool restoreGamma() override; // Restore original gamma table (before updating gamma) + + U32 getFSAASamples() override; + void setFSAASamples(const U32 samples) override; + + void processMiscNativeEvents() override; + + void gatherInput() override; + + SDL_AppResult handleEvent(const SDL_Event& event); + static SDL_AppResult handleEvents(const SDL_Event& event); + + void swapBuffers() override; + + void delayInputProcessing() override {}; // 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); + bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override; + bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override; + bool convertCoords(LLCoordWindow from, LLCoordGL *to) override; + bool convertCoords(LLCoordGL from, LLCoordWindow *to) override; + bool convertCoords(LLCoordScreen from, LLCoordGL *to) override; + bool convertCoords(LLCoordGL from, LLCoordScreen *to) override; + + LLWindowResolution *getSupportedResolutions(S32 &num_resolutions) override; - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); - /*virtual*/ F32 getNativeAspectRatio(); - /*virtual*/ F32 getPixelAspectRatio(); - /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } + F32 getNativeAspectRatio() override; + F32 getPixelAspectRatio() override; + void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } - /*virtual*/ void beforeDialog(); - /*virtual*/ void afterDialog(); + void beforeDialog() override; + void afterDialog() override; - /*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b); + bool dialogColorPicker(F32 *r, F32 *g, F32 *b) override; - /*virtual*/ void *getPlatformWindow(); - /*virtual*/ void bringToFront(); + void *getPlatformWindow() override; - /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); + void bringToFront() override; + + void setLanguageTextInput(const LLCoordGL& pos) override; + + void spawnWebBrowser(const std::string &escaped_url, bool async) override; + + void setTitle(const std::string title) override; static std::vector<std::string> 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); + void *createSharedContext() override; + void makeContextCurrent(void *context) override; + void destroySharedContext(void *context) override; + void toggleVSync(bool enable_vsync) override; -#if LL_GTK - // Lazily initialize and check the runtime GTK version for goodness. - static bool ll_try_gtk_init(void); -#endif // LL_GTK + F32 getSystemUISize() override; -#if LL_X11 - static Window get_SDL_XWindowID(void); - static Display* get_SDL_Display(void); -#endif // LL_X11 + static std::vector<std::string> getDisplaysResolutionList(); -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); - ~LLWindowSDL(); +#if LL_DARWIN + static U64 getVramSize(); + static void setUseMultGL(bool use_mult_gl); + + static bool sUseMultGL; +#endif - /*virtual*/ bool isValid(); - /*virtual*/ LLSD getNativeKeyData(); +protected: + LLWindowSDL(LLWindowCallbacks *callbacks, + const std::string &title, const std::string& name, int x, int y, int width, int height, U32 flags, + bool fullscreen, bool clearBg, bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples); - void initCursors(); - void quitCursors(); - void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); + ~LLWindowSDL(); - // Changes display resolution. Returns true if successful - bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + bool isValid() override; - // Go back to last fullscreen display resolution. - bool setFullscreenResolution(); + LLSD getNativeKeyData() override; - bool shouldPostQuit() { return mPostQuit; } + void initCursors(); + void quitCursors(); protected: // @@ -174,47 +195,67 @@ protected: // // 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); + bool createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync); void destroyContext(); - void setupFailure(const std::string& text, const std::string& caption, U32 type); - void fixWindowSize(void); - U32 SDLCheckGrabbyKeys(SDLKey keysym, bool gain); + + void setupFailure(const std::string &text, const std::string &caption, U32 type); + bool SDLReallyCaptureInput(bool capture); + U32 SDLCheckGrabbyKeys(U32 keysym, bool gain); // // Platform specific variables // - U32 mGrabbyKeyFlags; - int mReallyCapturedCount; - SDL_Surface * mWindow; - 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; + U32 mGrabbyKeyFlags = 0; + S32 mReallyCapturedCount = 0; + SDL_Window *mWindow = nullptr; + SDL_GLContext mContext; + SDL_Cursor *mSDLCursors[UI_CURSOR_COUNT]; - int mSDLFlags; - - SDL_Cursor* mSDLCursors[UI_CURSOR_COUNT]; - int mHaveInputFocus; /* 0=no, 1=yes, else unknown */ - int mIsMinimized; /* 0=no, 1=yes, else unknown */ + std::string mWindowTitle; + F32 mNativeAspectRatio = 0.0f; + F32 mOverrideAspectRatio = 0.0f; + F32 mGamma = 0.0f; + U32 mFSAASamples = 0; friend class LLWindowManager; private: -#if LL_X11 - void x11_set_urgent(bool urgent); - bool mFlashing; + bool mFlashing = false; LLTimer mFlashTimer; -#endif //LL_X11 + U32 mKeyVirtualKey = 0; + U32 mKeyModifiers = SDL_KMOD_NONE; - U32 mKeyScanCode; - U32 mKeyVirtualKey; - SDLMod mKeyModifiers; -}; + LLMutex mOSRMutex; + std::unordered_map<SDL_GLContext, SDL_Window*> mOSRContexts; + std::list<SDL_Window*> mDeadOSRWindows; + + void tryFindFullscreenSize(int &aWidth, int &aHeight); + enum EServerProtocol{ X11, Wayland, Unknown }; + EServerProtocol mServerProtocol = Unknown; +public: +#if LL_X11 + // X11 + struct X11_DATA + { + Display* xdisplay = nullptr; + Window xwindow = 0; + int xscreen = -1; + }; + static X11_DATA sX11Data; +#endif + +#if LL_WAYLAND + // Wayland + struct WAYLAND_DATA + { + struct wl_display* display = nullptr; + struct wl_surface* surface = nullptr; + }; + static WAYLAND_DATA sWaylandData; +#endif +}; class LLSplashScreenSDL : public LLSplashScreen { @@ -222,9 +263,9 @@ public: LLSplashScreenSDL(); virtual ~LLSplashScreenSDL(); - /*virtual*/ void showImpl(); - /*virtual*/ void updateImpl(const std::string& mesg); - /*virtual*/ void hideImpl(); + void showImpl() override; + void updateImpl(const std::string& mesg) override; + void hideImpl() override; }; S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 3c7b83bde4..e947948c57 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -227,6 +227,7 @@ HKL LLWindowWin32::sWinInputLocale = 0; DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE; DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); +HMODULE LLWindowWin32::sGLDLLHandle = nullptr; static HWND sWindowHandleForMessageBox = NULL; @@ -529,7 +530,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mWindowThread = new LLWindowWin32Thread(); //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways - LoadLibrary(L"opengl32.dll"); + sGLDLLHandle = LoadLibrary(L"opengl32.dll"); // Request high-performance GPU before creating OpenGL context // This increases probability of discrete GPU being used when @@ -1779,6 +1780,8 @@ const S32 max_format = (S32)num_formats - 1; return false; } + gGLManager.initWGL(); // Reinit WGL functions once we have our full context + if (!gGLManager.initGL()) { LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); @@ -5260,6 +5263,18 @@ F32 LLWindowWin32::getSystemUISize() } //static +PROC WINAPI LLWindowWin32::getProcAddress(const char* func) +{ + PROC ret_func = wglGetProcAddress(func); + if (!ret_func && sGLDLLHandle) + { + // Try to fallback to OpenGL32.dll + ret_func = GetProcAddress(sGLDLLHandle, func); + } + return ret_func; +} + +//static std::vector<std::string> LLWindowWin32::getDisplaysResolutionList() { return sMonitorInfo.getResolutionsList(); diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index defa90d1a3..956dd510dd 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -130,6 +130,7 @@ public: LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ); + static PROC WINAPI getProcAddress(const char* func); static std::vector<std::string> getDisplaysResolutionList(); static std::vector<std::string> getDynamicFallbackFontList(); static void setDPIAwareness(); @@ -265,6 +266,8 @@ protected: bool mMouseVanish; + static HMODULE sGLDLLHandle; + // Cached values of GetWindowRect and GetClientRect to be used by app thread void updateWindowRect(); RECT mRect; |
