diff options
| author | Erik Kundiman <erik@megapahit.org> | 2026-09-01 18:35:23 +0800 |
|---|---|---|
| committer | Erik Kundiman <erik@megapahit.org> | 2026-09-04 21:58:53 +0800 |
| commit | 00bb3bb6f07660bd914d29a1389342bb3060d254 (patch) | |
| tree | 431f574922494d2201718f13085f17bc6bd7fb42 /indra/llwindow | |
| parent | a8636720129952c10cf49ab80da21bf8b340b96c (diff) | |
| parent | 4ef9f8f14b35ed388c294d53767a0dca0e890924 (diff) | |
Merge remote-tracking branch 'secondlife/release/26.4' into 26.4
Diffstat (limited to 'indra/llwindow')
27 files changed, 2059 insertions, 1675 deletions
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 69f11991ea..e35fcff06e 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 @@ -48,6 +50,49 @@ set(viewer_HEADER_FILES llmousehandler.h ) +# Platform-specific files for IDE visibility (excluded from build on other platforms) +set(macosx_SOURCE_FILES + llkeyboardmacosx.cpp + llwindowmacosx.cpp + llwindowmacosx-objc.mm + llopenglview-objc.mm + ) + +set(macosx_HEADER_FILES + llkeyboardmacosx.h + llwindowmacosx.h + llwindowmacosx-objc.h + llwindowmacosx_iokit.h + llopenglview-objc.h + llappdelegate-objc.h + ) + +set(linux_SOURCE_FILES + llsdl.cpp + llkeyboardsdl.cpp + llwindowsdl.cpp + ) + +set(linux_HEADER_FILES + llsdl.h + llkeyboardsdl.h + llwindowsdl.h + ) + +set(windows_SOURCE_FILES + llwindowwin32.cpp + lldxhardware.cpp + llkeyboardwin32.cpp + lldragdropwin32.cpp + ) + +set(windows_HEADER_FILES + llwindowwin32.h + lldxhardware.h + llkeyboardwin32.h + lldragdropwin32.h + ) + set(llwindow_LINK_LIBRARIES llcommon llimage @@ -57,51 +102,22 @@ set(llwindow_LINK_LIBRARIES ll::glm ll::glext ll::uilibraries - ll::SDL ) include_directories(${CMAKE_SOURCE_DIR}/llrender) -# Libraries on which this library depends, needed for Linux builds -# Sort by high-level to low-level -if (NOT (DARWIN OR WINDOWS)) - list(APPEND viewer_SOURCE_FILES - llkeyboardsdl.cpp - llwindowsdl.cpp - ) - list(APPEND viewer_HEADER_FILES - llkeyboardsdl.h - llwindowsdl.h - ) +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) + list(APPEND llwindow_LINK_LIBRARIES + ll::SDL3 + ) endif () if (DARWIN) - list(APPEND llwindow_SOURCE_FILES - llkeyboardmacosx.cpp - llwindowmacosx.cpp - llwindowmacosx-objc.mm - llopenglview-objc.mm - ) - list(APPEND llwindow_HEADER_FILES - llkeyboardmacosx.h - llwindowmacosx.h - llwindowmacosx-objc.h - llopenglview-objc.h - llappdelegate-objc.h - ) + list(APPEND llwindow_SOURCE_FILES ${macosx_SOURCE_FILES}) + list(APPEND llwindow_HEADER_FILES ${macosx_HEADER_FILES}) # We use a bunch of deprecated system APIs. set_source_files_properties( @@ -110,22 +126,19 @@ if (DARWIN) PROPERTIES COMPILE_FLAGS "-fpascal-strings" ) + + set_source_files_properties( + llwindowmacosx-objc.mm + llopenglview-objc.mm + PROPERTIES + SKIP_PRECOMPILE_HEADERS TRUE + ) endif (DARWIN) if (WINDOWS) - list(APPEND llwindow_SOURCE_FILES - llwindowwin32.cpp - lldxhardware.cpp - llkeyboardwin32.cpp - lldragdropwin32.cpp - ) - list(APPEND llwindow_HEADER_FILES - llwindowwin32.h - lldxhardware.h - llkeyboardwin32.h - lldragdropwin32.h - ) + list(APPEND llwindow_SOURCE_FILES ${windows_SOURCE_FILES}) + list(APPEND llwindow_HEADER_FILES ${windows_HEADER_FILES}) list(APPEND llwindow_LINK_LIBRARIES comdlg32 # Common Dialogs for ChooseColor ole32 @@ -134,32 +147,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) @@ -168,19 +204,59 @@ endif (llwindow_HEADER_FILES) list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES}) + # Collect all platform files for IDE visibility, excluding already-added current platform + set(ide_visibility_files "") + if (NOT DARWIN) + list(APPEND ide_visibility_files ${macosx_SOURCE_FILES} ${macosx_HEADER_FILES}) + endif() + if (NOT (LINUX OR CMAKE_SYSTEM_NAME MATCHES FreeBSD)) + list(APPEND ide_visibility_files ${linux_SOURCE_FILES} ${linux_HEADER_FILES}) + endif() + if (NOT WINDOWS) + list(APPEND ide_visibility_files ${windows_SOURCE_FILES} ${windows_HEADER_FILES}) + endif() + add_library (llwindow ${llwindow_SOURCE_FILES} ${viewer_SOURCE_FILES} + # Add non-platform files for IDE visibility only + ${ide_visibility_files} ) -if (SDL_FOUND) - set_property(TARGET llwindow - PROPERTY COMPILE_DEFINITIONS LL_SDL=1 +# Mark non-platform files as excluded from build +if (WINDOWS) + set_source_files_properties( + ${macosx_SOURCE_FILES} + ${linux_SOURCE_FILES} + PROPERTIES + HEADER_FILE_ONLY TRUE + ) +elseif (DARWIN) + set_source_files_properties( + ${windows_SOURCE_FILES} + ${linux_SOURCE_FILES} + PROPERTIES + HEADER_FILE_ONLY TRUE + ) +elseif (LINUX OR CMAKE_SYSTEM_NAME MATCHES FreeBSD) + set_source_files_properties( + ${macosx_SOURCE_FILES} + ${windows_SOURCE_FILES} + PROPERTIES + HEADER_FILE_ONLY TRUE ) -endif (SDL_FOUND) +endif() + +target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES}) +target_include_directories(llwindow INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - 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() + +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 d9c1a9cf7d..df69b1390c 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -163,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 @@ -198,7 +199,6 @@ void LLKeyboard::resetKeys() bool LLKeyboard::translateKey(const NATIVE_KEY_TYPE os_key, KEY *out_key) { - // Only translate keys in the map, ignore all other keys for now auto iter = mTranslateKeyMap.find(os_key); if (iter == mTranslateKeyMap.end()) @@ -228,7 +228,7 @@ LLKeyboard::NATIVE_KEY_TYPE LLKeyboard::inverseTranslateKey(const KEY translated } -bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask) +bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key, MASK translated_mask) { bool handled = false; bool repeated = false; @@ -256,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 808be7b245..a092787cef 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -54,10 +54,12 @@ class LLWindowCallbacks; class LLKeyboard { public: -#ifndef LL_SDL - typedef U16 NATIVE_KEY_TYPE; -#else +#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(); @@ -72,14 +74,14 @@ public: bool getKeyRepeated(const KEY key) { return mKeyRepeated[key]; } bool translateKey(const NATIVE_KEY_TYPE os_key, KEY *translated_key); - NATIVE_KEY_TYPE inverseTranslateKey(const KEY translated_key); - bool handleTranslatedKeyUp(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes - bool handleTranslatedKeyDown(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes + 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 NATIVE_KEY_TYPE key, MASK mask) = 0; virtual bool handleKeyDown(const NATIVE_KEY_TYPE key, MASK mask) = 0; -#if defined(LL_DARWIN) && !defined(LL_SDL) +#if LL_DARWIN && !LL_SDL_WINDOW // We only actually use this for macOS. virtual void handleModifier(MASK mask) = 0; #endif // LL_DARWIN diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp index 6f8c829dd5..50d03aaf20 100644 --- a/indra/llwindow/llkeyboardheadless.cpp +++ b/indra/llwindow/llkeyboardheadless.cpp @@ -31,17 +31,23 @@ LLKeyboardHeadless::LLKeyboardHeadless() { } -void LLKeyboardHeadless::resetMaskKeys() -{ } - - +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; +} +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) { @@ -61,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 439abaf25b..364fb03fe7 100644 --- a/indra/llwindow/llkeyboardheadless.h +++ b/indra/llwindow/llkeyboardheadless.h @@ -33,20 +33,15 @@ class LLKeyboardHeadless : public LLKeyboard { public: LLKeyboardHeadless(); - /*virtual*/ ~LLKeyboardHeadless() {}; + ~LLKeyboardHeadless() = default; -#ifndef LL_SDL - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask) { return false; } - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask) { return false; } -#else - /*virtual*/ bool handleKeyUp(const U32 key, MASK mask) { return false; } - /*virtual*/ bool handleKeyDown(const U32 key, MASK mask) { return false; } -#endif - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); -#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 101e035135..7d270a4392 100644 --- a/indra/llwindow/llkeyboardmacosx.cpp +++ b/indra/llwindow/llkeyboardmacosx.cpp @@ -196,7 +196,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. @@ -221,7 +221,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; @@ -237,7 +237,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; @@ -260,7 +260,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; @@ -277,7 +277,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; @@ -296,7 +296,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; @@ -325,6 +325,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 c8805300cb..d951ce331e 100644 --- a/indra/llwindow/llkeyboardsdl.cpp +++ b/indra/llwindow/llkeyboardsdl.cpp @@ -1,5 +1,6 @@ /** - * @author This module has many fathers, and it shows. + * @file llkeyboardsdl.cpp + * @brief Handler for assignable key bindings * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code @@ -27,8 +28,8 @@ #include "linden_common.h" #include "llkeyboardsdl.h" #include "llwindowcallbacks.h" -#include "SDL2/SDL.h" -#include "SDL2/SDL_keycode.h" + +#include "SDL3/SDL_keycode.h" LLKeyboardSDL::LLKeyboardSDL() { @@ -39,11 +40,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... - - // <FS:ND> Looks like we need to map those despite of SDL_TEXTINPUT handling most of this, but without - // the translation lower->upper here accelerators will not work. - - U16 cur_char; + LLKeyboard::NATIVE_KEY_TYPE cur_char; for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) { mTranslateKeyMap[cur_char] = cur_char; @@ -71,7 +68,7 @@ LLKeyboardSDL::LLKeyboardSDL() //mTranslateKeyMap[SDLK_KP3] = KEY_PAGE_DOWN; //mTranslateKeyMap[SDLK_KP0] = KEY_INSERT; - mTranslateKeyMap[SDLK_SPACE] = ' '; // <FS:ND/> Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_SPACE] = ' '; mTranslateKeyMap[SDLK_RETURN] = KEY_RETURN; mTranslateKeyMap[SDLK_LEFT] = KEY_LEFT; mTranslateKeyMap[SDLK_RIGHT] = KEY_RIGHT; @@ -113,17 +110,17 @@ LLKeyboardSDL::LLKeyboardSDL() mTranslateKeyMap[SDLK_F10] = KEY_F10; mTranslateKeyMap[SDLK_F11] = KEY_F11; mTranslateKeyMap[SDLK_F12] = KEY_F12; - mTranslateKeyMap[SDLK_PLUS] = '='; // <FS:ND/> Those are handled by SDL2 via text input, do not map them - mTranslateKeyMap[SDLK_COMMA] = ','; // <FS:ND/> Those are handled by SDL2 via text input, do not map them - mTranslateKeyMap[SDLK_MINUS] = '-'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them - mTranslateKeyMap[SDLK_PERIOD] = '.'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them - mTranslateKeyMap[SDLK_BACKQUOTE] = '`'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them - mTranslateKeyMap[SDLK_SLASH] = KEY_DIVIDE; // <FS:ND/> Those are handled by SDL2 via text input, do not map them - mTranslateKeyMap[SDLK_SEMICOLON] = ';'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them - mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; // <FS:ND/> Those are handled by SDL2 via text input, do not map them - mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them - mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them - mTranslateKeyMap[SDLK_QUOTE] = '\''; // <FS:ND/> Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_PLUS] = '='; + mTranslateKeyMap[SDLK_COMMA] = ','; + mTranslateKeyMap[SDLK_MINUS] = '-'; + mTranslateKeyMap[SDLK_PERIOD] = '.'; + mTranslateKeyMap[SDLK_GRAVE] = '`'; + mTranslateKeyMap[SDLK_SLASH] = KEY_DIVIDE; + mTranslateKeyMap[SDLK_SEMICOLON] = ';'; + mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; + mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; + mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; + mTranslateKeyMap[SDLK_APOSTROPHE] = '\''; // Build inverse map for (auto iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) @@ -161,12 +158,12 @@ void LLKeyboardSDL::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 #ifdef LL_DARWIN | KMOD_GUI #endif @@ -175,24 +172,24 @@ void LLKeyboardSDL::resetMaskKeys() 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 #ifdef LL_DARWIN | KMOD_GUI #endif @@ -201,7 +198,7 @@ MASK LLKeyboardSDL::updateModifiers(const U32 mask) out_mask |= MASK_CONTROL; } - if(mask & KMOD_ALT) + if(mask & SDL_KMOD_ALT) { out_mask |= MASK_ALT; } @@ -210,12 +207,12 @@ MASK LLKeyboardSDL::updateModifiers(const U32 mask) } -static U32 adjustNativekeyFromUnhandledMask(const U32 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. - U32 rtn = key; - if (!(mask & KMOD_NUM)) + LLKeyboard::NATIVE_KEY_TYPE rtn = key; + if (!(mask & SDL_KMOD_NUM)) { switch (key) { @@ -235,12 +232,12 @@ static U32 adjustNativekeyFromUnhandledMask(const U32 key, const U32 mask) } -bool LLKeyboardSDL::handleKeyDown(const U32 key, const U32 mask) +bool LLKeyboardSDL::handleKeyDown(const LLKeyboard::NATIVE_KEY_TYPE key, const MASK mask) { - U32 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); @@ -255,12 +252,12 @@ bool LLKeyboardSDL::handleKeyDown(const U32 key, const U32 mask) } -bool LLKeyboardSDL::handleKeyUp(const U32 key, const U32 mask) +bool LLKeyboardSDL::handleKeyUp(const LLKeyboard::NATIVE_KEY_TYPE key, const MASK mask) { - U32 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); @@ -279,17 +276,17 @@ MASK LLKeyboardSDL::currentMask(bool for_mouse_event) MASK result = MASK_NONE; SDL_Keymod mask = SDL_GetModState(); - if (mask & KMOD_SHIFT) + if (mask & SDL_KMOD_SHIFT) result |= MASK_SHIFT; - if (mask & KMOD_CTRL) + if (mask & SDL_KMOD_CTRL) result |= MASK_CONTROL; - if (mask & KMOD_ALT) + if (mask & SDL_KMOD_ALT) result |= MASK_ALT; // For keyboard events, consider Meta keys equivalent to Control if (!for_mouse_event) { - if (mask & KMOD_GUI) + if (mask & SDL_KMOD_GUI) result |= MASK_CONTROL; } @@ -309,6 +306,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++) @@ -323,347 +321,346 @@ void LLKeyboardSDL::scanKeyboard() } -bool LLKeyboardSDL::translateNumpadKey( const U32 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); } enum class WindowsVK : U32 { - VK_UNKNOWN = 0, - VK_CANCEL = 0x03, - VK_BACK = 0x08, - VK_TAB = 0x09, - VK_CLEAR = 0x0C, - VK_RETURN = 0x0D, - VK_SHIFT = 0x10, - VK_CONTROL = 0x11, - VK_MENU = 0x12, - VK_PAUSE = 0x13, - VK_CAPITAL = 0x14, - VK_KANA = 0x15, - VK_HANGUL = 0x15, - VK_JUNJA = 0x17, - VK_FINAL = 0x18, - VK_HANJA = 0x19, - VK_KANJI = 0x19, - VK_ESCAPE = 0x1B, - VK_CONVERT = 0x1C, - VK_NONCONVERT = 0x1D, - VK_ACCEPT = 0x1E, - VK_MODECHANGE = 0x1F, - VK_SPACE = 0x20, - VK_PRIOR = 0x21, - VK_NEXT = 0x22, - VK_END = 0x23, - VK_HOME = 0x24, - VK_LEFT = 0x25, - VK_UP = 0x26, - VK_RIGHT = 0x27, - VK_DOWN = 0x28, - VK_SELECT = 0x29, - VK_PRINT = 0x2A, - VK_EXECUTE = 0x2B, - VK_SNAPSHOT = 0x2C, - VK_INSERT = 0x2D, - VK_DELETE = 0x2E, - VK_HELP = 0x2F, - VK_0 = 0x30, - VK_1 = 0x31, - VK_2 = 0x32, - VK_3 = 0x33, - VK_4 = 0x34, - VK_5 = 0x35, - VK_6 = 0x36, - VK_7 = 0x37, - VK_8 = 0x38, - VK_9 = 0x39, - VK_A = 0x41, - VK_B = 0x42, - VK_C = 0x43, - VK_D = 0x44, - VK_E = 0x45, - VK_F = 0x46, - VK_G = 0x47, - VK_H = 0x48, - VK_I = 0x49, - VK_J = 0x4A, - VK_K = 0x4B, - VK_L = 0x4C, - VK_M = 0x4D, - VK_N = 0x4E, - VK_O = 0x4F, - VK_P = 0x50, - VK_Q = 0x51, - VK_R = 0x52, - VK_S = 0x53, - VK_T = 0x54, - VK_U = 0x55, - VK_V = 0x56, - VK_W = 0x57, - VK_X = 0x58, - VK_Y = 0x59, - VK_Z = 0x5A, - VK_LWIN = 0x5B, - VK_RWIN = 0x5C, - VK_APPS = 0x5D, - VK_SLEEP = 0x5F, - VK_NUMPAD0 = 0x60, - VK_NUMPAD1 = 0x61, - VK_NUMPAD2 = 0x62, - VK_NUMPAD3 = 0x63, - VK_NUMPAD4 = 0x64, - VK_NUMPAD5 = 0x65, - VK_NUMPAD6 = 0x66, - VK_NUMPAD7 = 0x67, - VK_NUMPAD8 = 0x68, - VK_NUMPAD9 = 0x69, - VK_MULTIPLY = 0x6A, - VK_ADD = 0x6B, - VK_SEPARATOR = 0x6C, - VK_SUBTRACT = 0x6D, - VK_DECIMAL = 0x6E, - VK_DIVIDE = 0x6F, - VK_F1 = 0x70, - VK_F2 = 0x71, - VK_F3 = 0x72, - VK_F4 = 0x73, - VK_F5 = 0x74, - VK_F6 = 0x75, - VK_F7 = 0x76, - VK_F8 = 0x77, - VK_F9 = 0x78, - VK_F10 = 0x79, - VK_F11 = 0x7A, - VK_F12 = 0x7B, - VK_F13 = 0x7C, - VK_F14 = 0x7D, - VK_F15 = 0x7E, - VK_F16 = 0x7F, - VK_F17 = 0x80, - VK_F18 = 0x81, - VK_F19 = 0x82, - VK_F20 = 0x83, - VK_F21 = 0x84, - VK_F22 = 0x85, - VK_F23 = 0x86, - VK_F24 = 0x87, - VK_NUMLOCK = 0x90, - VK_SCROLL = 0x91, - VK_LSHIFT = 0xA0, - VK_RSHIFT = 0xA1, - VK_LCONTROL = 0xA2, - VK_RCONTROL = 0xA3, - VK_LMENU = 0xA4, - VK_RMENU = 0xA5, - VK_BROWSER_BACK = 0xA6, - VK_BROWSER_FORWARD = 0xA7, - VK_BROWSER_REFRESH = 0xA8, - VK_BROWSER_STOP = 0xA9, - VK_BROWSER_SEARCH = 0xAA, - VK_BROWSER_FAVORITES = 0xAB, - VK_BROWSER_HOME = 0xAC, - VK_VOLUME_MUTE = 0xAD, - VK_VOLUME_DOWN = 0xAE, - VK_VOLUME_UP = 0xAF, - VK_MEDIA_NEXT_TRACK = 0xB0, - VK_MEDIA_PREV_TRACK = 0xB1, - VK_MEDIA_STOP = 0xB2, - VK_MEDIA_PLAY_PAUSE = 0xB3, - VK_MEDIA_LAUNCH_MAIL = 0xB4, - VK_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5, - VK_MEDIA_LAUNCH_APP1 = 0xB6, - VK_MEDIA_LAUNCH_APP2 = 0xB7, - VK_OEM_1 = 0xBA, - VK_OEM_PLUS = 0xBB, - VK_OEM_COMMA = 0xBC, - VK_OEM_MINUS = 0xBD, - VK_OEM_PERIOD = 0xBE, - VK_OEM_2 = 0xBF, - VK_OEM_3 = 0xC0, - VK_OEM_4 = 0xDB, - VK_OEM_5 = 0xDC, - VK_OEM_6 = 0xDD, - VK_OEM_7 = 0xDE, - VK_OEM_8 = 0xDF, - VK_OEM_102 = 0xE2, - VK_PROCESSKEY = 0xE5, - VK_PACKET = 0xE7, - VK_ATTN = 0xF6, - VK_CRSEL = 0xF7, - VK_EXSEL = 0xF8, - VK_EREOF = 0xF9, - VK_PLAY = 0xFA, - VK_ZOOM = 0xFB, - VK_NONAME = 0xFC, - VK_PA1 = 0xFD, - VK_OEM_CLEAR = 0xFE, + 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 > mSDL2_to_Win; -std::set< U32 > mIgnoreSDL2Keys; +std::map< U32, U32 > mSDL_to_Win; -U32 LLKeyboardSDL::mapSDL2toWin( U32 aSymbol ) +U32 LLKeyboardSDL::mapSDLtoWin( U32 aSymbol ) { - // <FS:ND> Map SDLK_ virtual keys to Windows VK_ virtual keys. - // Text is handled via unicode input (SDL_TEXTINPUT event) and does not need to be translated into VK_ values as those match already. - if( mSDL2_to_Win.empty() ) + // <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() ) { - mSDL2_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::VK_BACK; - mSDL2_to_Win[ SDLK_TAB ] = (U32)WindowsVK::VK_TAB; - mSDL2_to_Win[ 12 ] = (U32)WindowsVK::VK_CLEAR; - mSDL2_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::VK_RETURN; - mSDL2_to_Win[ 19 ] = (U32)WindowsVK::VK_PAUSE; - mSDL2_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::VK_ESCAPE; - mSDL2_to_Win[ SDLK_SPACE ] = (U32)WindowsVK::VK_SPACE; - mSDL2_to_Win[ SDLK_QUOTE ] = (U32)WindowsVK::VK_OEM_7; - mSDL2_to_Win[ SDLK_COMMA ] = (U32)WindowsVK::VK_OEM_COMMA; - mSDL2_to_Win[ SDLK_MINUS ] = (U32)WindowsVK::VK_OEM_MINUS; - mSDL2_to_Win[ SDLK_PERIOD ] = (U32)WindowsVK::VK_OEM_PERIOD; - mSDL2_to_Win[ SDLK_SLASH ] = (U32)WindowsVK::VK_OEM_2; + 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; - mSDL2_to_Win[ SDLK_0 ] = (U32)WindowsVK::VK_0; - mSDL2_to_Win[ SDLK_1 ] = (U32)WindowsVK::VK_1; - mSDL2_to_Win[ SDLK_2 ] = (U32)WindowsVK::VK_2; - mSDL2_to_Win[ SDLK_3 ] = (U32)WindowsVK::VK_3; - mSDL2_to_Win[ SDLK_4 ] = (U32)WindowsVK::VK_4; - mSDL2_to_Win[ SDLK_5 ] = (U32)WindowsVK::VK_5; - mSDL2_to_Win[ SDLK_6 ] = (U32)WindowsVK::VK_6; - mSDL2_to_Win[ SDLK_7 ] = (U32)WindowsVK::VK_7; - mSDL2_to_Win[ SDLK_8 ] = (U32)WindowsVK::VK_8; - mSDL2_to_Win[ SDLK_9 ] = (U32)WindowsVK::VK_9; + 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; - mSDL2_to_Win[ SDLK_SEMICOLON ] = (U32)WindowsVK::VK_OEM_1; - mSDL2_to_Win[ SDLK_LESS ] = (U32)WindowsVK::VK_OEM_102; - mSDL2_to_Win[ SDLK_EQUALS ] = (U32)WindowsVK::VK_OEM_PLUS; - mSDL2_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::VK_OEM_PLUS; + 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; - mSDL2_to_Win[ SDLK_LEFTBRACKET ] = (U32)WindowsVK::VK_OEM_4; - mSDL2_to_Win[ SDLK_BACKSLASH ] = (U32)WindowsVK::VK_OEM_5; - mSDL2_to_Win[ SDLK_RIGHTBRACKET ] = (U32)WindowsVK::VK_OEM_6; - mSDL2_to_Win[ SDLK_BACKQUOTE ] = (U32)WindowsVK::VK_OEM_8; + 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; - mSDL2_to_Win[ SDLK_a ] = (U32)WindowsVK::VK_A; - mSDL2_to_Win[ SDLK_b ] = (U32)WindowsVK::VK_B; - mSDL2_to_Win[ SDLK_c ] = (U32)WindowsVK::VK_C; - mSDL2_to_Win[ SDLK_d ] = (U32)WindowsVK::VK_D; - mSDL2_to_Win[ SDLK_e ] = (U32)WindowsVK::VK_E; - mSDL2_to_Win[ SDLK_f ] = (U32)WindowsVK::VK_F; - mSDL2_to_Win[ SDLK_g ] = (U32)WindowsVK::VK_G; - mSDL2_to_Win[ SDLK_h ] = (U32)WindowsVK::VK_H; - mSDL2_to_Win[ SDLK_i ] = (U32)WindowsVK::VK_I; - mSDL2_to_Win[ SDLK_j ] = (U32)WindowsVK::VK_J; - mSDL2_to_Win[ SDLK_k ] = (U32)WindowsVK::VK_K; - mSDL2_to_Win[ SDLK_l ] = (U32)WindowsVK::VK_L; - mSDL2_to_Win[ SDLK_m ] = (U32)WindowsVK::VK_M; - mSDL2_to_Win[ SDLK_n ] = (U32)WindowsVK::VK_N; - mSDL2_to_Win[ SDLK_o ] = (U32)WindowsVK::VK_O; - mSDL2_to_Win[ SDLK_p ] = (U32)WindowsVK::VK_P; - mSDL2_to_Win[ SDLK_q ] = (U32)WindowsVK::VK_Q; - mSDL2_to_Win[ SDLK_r ] = (U32)WindowsVK::VK_R; - mSDL2_to_Win[ SDLK_s ] = (U32)WindowsVK::VK_S; - mSDL2_to_Win[ SDLK_t ] = (U32)WindowsVK::VK_T; - mSDL2_to_Win[ SDLK_u ] = (U32)WindowsVK::VK_U; - mSDL2_to_Win[ SDLK_v ] = (U32)WindowsVK::VK_V; - mSDL2_to_Win[ SDLK_w ] = (U32)WindowsVK::VK_W; - mSDL2_to_Win[ SDLK_x ] = (U32)WindowsVK::VK_X; - mSDL2_to_Win[ SDLK_y ] = (U32)WindowsVK::VK_Y; - mSDL2_to_Win[ SDLK_z ] = (U32)WindowsVK::VK_Z; + 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; - mSDL2_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::VK_DELETE; + mSDL_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::LL_VK_DELETE; - mSDL2_to_Win[ SDLK_NUMLOCKCLEAR ] = (U32)WindowsVK::VK_NUMLOCK; - mSDL2_to_Win[ SDLK_SCROLLLOCK ] = (U32)WindowsVK::VK_SCROLL; + mSDL_to_Win[ SDLK_NUMLOCKCLEAR ] = (U32)WindowsVK::LL_VK_NUMLOCK; + mSDL_to_Win[ SDLK_SCROLLLOCK ] = (U32)WindowsVK::LL_VK_SCROLL; - mSDL2_to_Win[ SDLK_HELP ] = (U32)WindowsVK::VK_HELP; - mSDL2_to_Win[ SDLK_PRINTSCREEN ] = (U32)WindowsVK::VK_SNAPSHOT; - mSDL2_to_Win[ SDLK_CANCEL ] = (U32)WindowsVK::VK_CANCEL; - mSDL2_to_Win[ SDLK_APPLICATION ] = (U32)WindowsVK::VK_APPS; + 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; - mSDL2_to_Win[ SDLK_UNKNOWN ] = (U32)WindowsVK::VK_UNKNOWN; - mSDL2_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::VK_BACK; - mSDL2_to_Win[ SDLK_TAB ] = (U32)WindowsVK::VK_TAB; - mSDL2_to_Win[ SDLK_CLEAR ] = (U32)WindowsVK::VK_CLEAR; - mSDL2_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::VK_RETURN; - mSDL2_to_Win[ SDLK_PAUSE ] = (U32)WindowsVK::VK_PAUSE; - mSDL2_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::VK_ESCAPE; - mSDL2_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::VK_DELETE; + 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; - mSDL2_to_Win[ SDLK_KP_PERIOD ] = (U32)WindowsVK::VK_OEM_PERIOD; // VK_DECIMAL? - mSDL2_to_Win[ SDLK_KP_DIVIDE ] = (U32)WindowsVK::VK_DIVIDE; - mSDL2_to_Win[ SDLK_KP_MULTIPLY] = (U32)WindowsVK::VK_MULTIPLY; - mSDL2_to_Win[ SDLK_KP_MINUS ] = (U32)WindowsVK::VK_OEM_MINUS; // VK_SUBSTRACT? - mSDL2_to_Win[ SDLK_KP_PLUS ] = (U32)WindowsVK::VK_OEM_PLUS; // VK_ADD? - mSDL2_to_Win[ SDLK_KP_ENTER ] = (U32)WindowsVK::VK_RETURN; - mSDL2_to_Win[ SDLK_KP_0 ] = (U32)WindowsVK::VK_NUMPAD0; - mSDL2_to_Win[ SDLK_KP_1 ] = (U32)WindowsVK::VK_NUMPAD1; - mSDL2_to_Win[ SDLK_KP_2 ] = (U32)WindowsVK::VK_NUMPAD2; - mSDL2_to_Win[ SDLK_KP_3 ] = (U32)WindowsVK::VK_NUMPAD3; - mSDL2_to_Win[ SDLK_KP_4 ] = (U32)WindowsVK::VK_NUMPAD4; - mSDL2_to_Win[ SDLK_KP_5 ] = (U32)WindowsVK::VK_NUMPAD5; - mSDL2_to_Win[ SDLK_KP_6 ] = (U32)WindowsVK::VK_NUMPAD6; - mSDL2_to_Win[ SDLK_KP_7 ] = (U32)WindowsVK::VK_NUMPAD7; - mSDL2_to_Win[ SDLK_KP_8 ] = (U32)WindowsVK::VK_NUMPAD8; - mSDL2_to_Win[ SDLK_KP_9 ] = (U32)WindowsVK::VK_NUMPAD9; + 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; // ? - mSDL2_to_Win[ SDLK_UP ] = (U32)WindowsVK::VK_UP; - mSDL2_to_Win[ SDLK_DOWN ] = (U32)WindowsVK::VK_DOWN; - mSDL2_to_Win[ SDLK_RIGHT ] = (U32)WindowsVK::VK_RIGHT; - mSDL2_to_Win[ SDLK_LEFT ] = (U32)WindowsVK::VK_LEFT; - mSDL2_to_Win[ SDLK_INSERT ] = (U32)WindowsVK::VK_INSERT; - mSDL2_to_Win[ SDLK_HOME ] = (U32)WindowsVK::VK_HOME; - mSDL2_to_Win[ SDLK_END ] = (U32)WindowsVK::VK_END; - mSDL2_to_Win[ SDLK_PAGEUP ] = (U32)WindowsVK::VK_PRIOR; - mSDL2_to_Win[ SDLK_PAGEDOWN ] = (U32)WindowsVK::VK_NEXT; - mSDL2_to_Win[ SDLK_F1 ] = (U32)WindowsVK::VK_F1; - mSDL2_to_Win[ SDLK_F2 ] = (U32)WindowsVK::VK_F2; - mSDL2_to_Win[ SDLK_F3 ] = (U32)WindowsVK::VK_F3; - mSDL2_to_Win[ SDLK_F4 ] = (U32)WindowsVK::VK_F4; - mSDL2_to_Win[ SDLK_F5 ] = (U32)WindowsVK::VK_F5; - mSDL2_to_Win[ SDLK_F6 ] = (U32)WindowsVK::VK_F6; - mSDL2_to_Win[ SDLK_F7 ] = (U32)WindowsVK::VK_F7; - mSDL2_to_Win[ SDLK_F8 ] = (U32)WindowsVK::VK_F8; - mSDL2_to_Win[ SDLK_F9 ] = (U32)WindowsVK::VK_F9; - mSDL2_to_Win[ SDLK_F10 ] = (U32)WindowsVK::VK_F10; - mSDL2_to_Win[ SDLK_F11 ] = (U32)WindowsVK::VK_F11; - mSDL2_to_Win[ SDLK_F12 ] = (U32)WindowsVK::VK_F12; - mSDL2_to_Win[ SDLK_F13 ] = (U32)WindowsVK::VK_F13; - mSDL2_to_Win[ SDLK_F14 ] = (U32)WindowsVK::VK_F14; - mSDL2_to_Win[ SDLK_F15 ] = (U32)WindowsVK::VK_F15; - mSDL2_to_Win[ SDLK_CAPSLOCK ] = (U32)WindowsVK::VK_CAPITAL; - mSDL2_to_Win[ SDLK_RSHIFT ] = (U32)WindowsVK::VK_SHIFT; - mSDL2_to_Win[ SDLK_LSHIFT ] = (U32)WindowsVK::VK_SHIFT; - mSDL2_to_Win[ SDLK_RCTRL ] = (U32)WindowsVK::VK_CONTROL; - mSDL2_to_Win[ SDLK_LCTRL ] = (U32)WindowsVK::VK_CONTROL; - mSDL2_to_Win[ SDLK_RALT ] = (U32)WindowsVK::VK_MENU; - mSDL2_to_Win[ SDLK_LALT ] = (U32)WindowsVK::VK_MENU; + 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; - mSDL2_to_Win[ SDLK_MENU ] = (U32)WindowsVK::VK_MENU; + mSDL_to_Win[ SDLK_MENU ] = (U32)WindowsVK::LL_VK_MENU; - // VK_MODECHANGE ? - // mSDL2_to_Win[ SDLK_MODE ] = (U32)WindowsVK::VK_MODE; + // LL_VK_MODECHANGE ? + // mSDL_to_Win[ SDLK_MODE ] = (U32)WindowsVK::LL_VK_MODE; // ? - // mSDL2_to_Win[ SDLK_SYSREQ ] = (U32)WindowsVK::VK_SYSREQ; - // mSDL2_to_Win[ SDLK_POWER ] = (U32)WindowsVK::VK_POWER; - // mSDL2_to_Win[ SDLK_UNDO ] = (U32)WindowsVK::VK_UNDO; - // mSDL2_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::VK_EQUALS; - // mSDL2_to_Win[ 311 ] = (U32)WindowsVK::VK_LWIN; - // mSDL2_to_Win[ 312 ] = (U32)WindowsVK::VK_RWIN; - // mSDL2_to_Win[ SDLK_COLON ] = ? + // 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 = mSDL2_to_Win.find( aSymbol ); - if( itr != mSDL2_to_Win.end() ) + 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 3af098c4d1..2ebe647561 100644 --- a/indra/llwindow/llkeyboardsdl.h +++ b/indra/llwindow/llkeyboardsdl.h @@ -1,7 +1,8 @@ /** - * @author This module has many fathers, and it shows. + * @file llkeyboardsdl.h + * @brief Handler for assignable key bindings * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * @@ -23,38 +24,35 @@ * $/LicenseInfo$ */ -#ifndef LL_LLKEYBOARDSDL2_H -#define LL_LLKEYBOARDSDL2_H +#ifndef LL_LLKEYBOARDSDL_H +#define LL_LLKEYBOARDSDL_H #include "llkeyboard.h" -#if !defined(__i386__) && !defined(__x86_64__) -#define SDL_DISABLE_IMMINTRIN_H -#endif -#include "SDL2/SDL.h" +#include "SDL3/SDL.h" class LLKeyboardSDL : public LLKeyboard { public: LLKeyboardSDL(); - /*virtual*/ ~LLKeyboardSDL() {}; + ~LLKeyboardSDL() = default; - /*virtual*/ bool handleKeyUp(const U32 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U32 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); + 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 U32 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<U32, KEY> mTranslateNumpadMap; // special map for translating OS keys to numpad keys - std::map<KEY, U32> 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 mapSDL2toWin( U32 ); + 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 935050485f..b6177abfc7 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 +#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); #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,7 +256,7 @@ bool LLWindow::copyTextToPrimary(const LLWString &src) // static std::vector<std::string> LLWindow::getDynamicFallbackFontList() { -#if LL_SDL +#if LL_SDL_WINDOW && !LL_MESA_HEADLESS return LLWindowSDL::getDynamicFallbackFontList(); #elif LL_WINDOWS return LLWindowWin32::getDynamicFallbackFontList(); @@ -270,14 +268,30 @@ std::vector<std::string> LLWindow::getDynamicFallbackFontList() } // static +LLFontFallbackMatch LLWindow::findFallbackFontForChar(llwchar wch) +{ +#if LL_SDL_WINDOW && !LL_MESA_HEADLESS + return LLWindowSDL::findFallbackFontForChar(wch); +#elif LL_WINDOWS + return LLWindowWin32::findFallbackFontForChar(wch); +#elif LL_DARWIN + return LLWindowMacOSX::findFallbackFontForChar(wch); +#else + return LLFontFallbackMatch(); +#endif +} + +// static std::vector<std::string> LLWindow::getDisplaysResolutionList() { -#if LL_SDL - return std::vector<std::string>(); +#if LL_SDL_WINDOW && !LL_MESA_HEADLESS + return LLWindowSDL::getDisplaysResolutionList(); #elif LL_WINDOWS return LLWindowWin32::getDisplaysResolutionList(); #elif LL_DARWIN return LLWindowMacOSX::getDisplaysResolutionList(); +#else + return std::vector<std::string>(); #endif } @@ -341,14 +355,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,9 +375,11 @@ void LLSplashScreen::show() { if (!gSplashScreenp) { -#if LL_WINDOWS && !LL_MESA_HEADLESS && !LL_SDL +#if LL_SDL_WINDOW && !LL_MESA_HEADLESS + gSplashScreenp = new LLSplashScreenSDL; +#elif LL_WINDOWS && !LL_MESA_HEADLESS gSplashScreenp = new LLSplashScreenWin32; -#elif LL_DARWIN && !LL_SDL +#elif LL_DARWIN gSplashScreenp = new LLSplashScreenMacOSX; #endif if (gSplashScreenp) @@ -410,7 +429,11 @@ LLWindow* LLWindowManager::createWindow( U32 max_cores, F32 max_gl_version) { - LLWindow* new_window = nullptr; + LLWindow* new_window; + +#if LL_SDL_WINDOW && !defined(LL_MESA_HEADLESS) + init_sdl(name); +#endif if (use_gl) { @@ -418,7 +441,7 @@ LLWindow* LLWindowManager::createWindow( 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, name, x, y, width, height, flags, fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); @@ -461,6 +484,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 80bfd60cd1..327323b018 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -38,6 +38,13 @@ class LLSplashScreen; class LLPreeditor; class LLWindowCallbacks; +// Result of an OS font-fallback query; empty mPath means no font was found. +struct LLFontFallbackMatch +{ + std::string mPath; + S32 mFaceIndex = 0; +}; + // Refer to llwindow_test in test/common/llwindow for usage example class LLWindow : public LLInstanceTracker<LLWindow> @@ -92,7 +99,7 @@ public: virtual bool setCursorPosition(LLCoordWindow position) = 0; virtual bool getCursorPosition(LLCoordWindow *position) = 0; -#if LL_WINDOWS && !LL_SDL +#if LL_WINDOWS && !LL_SDL_WINDOW virtual bool getCursorDelta(LLCoordCommon* delta) = 0; #endif virtual bool isWrapMouse() const = 0; @@ -174,9 +181,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 ) {}; @@ -186,6 +190,9 @@ public: static std::vector<std::string> getDynamicFallbackFontList(); + // Ask the OS for a font file covering the given codepoint (lazy fallback). + static LLFontFallbackMatch findFallbackFontForChar(llwchar wch); + // Provide native key event data virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 4b804c82cc..f997aebb9d 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -68,6 +68,18 @@ void LLWindowCallbacks::handleMouseLeave(LLWindow *window) return; } +void LLWindowCallbacks::handlePreCloseRequest() +{ +} + +void LLWindowCallbacks::handleCloseRequestCanceled() +{ +} + +void LLWindowCallbacks::handleSuspendRequest() +{ +} + bool LLWindowCallbacks::handleCloseRequest(LLWindow *window, bool from_user) { //allow the window to close diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 6d1990e92b..cd54ccd7c9 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -41,6 +41,10 @@ public: virtual bool handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); virtual bool handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); virtual void handleMouseLeave(LLWindow *window); + // Called before close request is processed (ex: to create marker file in case OS is about to kill app). + virtual void handlePreCloseRequest(); + virtual void handleCloseRequestCanceled(); + virtual void handleSuspendRequest(); // return true to allow window to close, which will then cause handleQuit to be called virtual bool handleCloseRequest(LLWindow *window, bool from_user); virtual bool handleSessionExit(LLWindow* window); diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index 0a1ecb05e0..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 && !LL_SDL +#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.cpp b/indra/llwindow/llwindowmacosx.cpp index 5a85887143..ce2f3cf9e2 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -44,7 +44,7 @@ #include <CoreGraphics/CGDisplayConfiguration.h> #include <IOKit/IOCFPlugIn.h> -#include <IOKit/IOKitLib.h> +#include "llwindowmacosx_iokit.h" #include <IOKit/IOMessage.h> #include <IOKit/hid/IOHIDUsageTables.h> #include <IOKit/hid/IOHIDLib.h> @@ -2383,7 +2383,7 @@ bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, io_iterator_t io_iter = 0; // create an IO object iterator - result = IOServiceGetMatchingServices( kIOMasterPortDefault, device_dict_ref, &io_iter ); + result = IOServiceGetMatchingServices( kLLIOMainPort, device_dict_ref, &io_iter ); if ( kIOReturnSuccess != result ) { LL_WARNS("Joystick") << "IOServiceGetMatchingServices failed" << LL_ENDL; @@ -2637,6 +2637,12 @@ std::vector<std::string> LLWindowMacOSX::getDynamicFallbackFontList() return std::vector<std::string>(); } +LLFontFallbackMatch LLWindowMacOSX::findFallbackFontForChar(llwchar wch) +{ + // Not implemented on macOS; would use CoreText (CTFontCreateForString). + return LLFontFallbackMatch(); +} + // static MASK LLWindowMacOSX::modifiersToMask(S16 modifiers) { diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index d703a84d02..9534eadf8e 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: @@ -122,6 +117,7 @@ public: static std::vector<std::string> getDisplaysResolutionList(); static std::vector<std::string> getDynamicFallbackFontList(); + static LLFontFallbackMatch findFallbackFontForChar(llwchar wch); // Provide native key event data LLSD getNativeKeyData() override; diff --git a/indra/llwindow/llwindowmacosx_iokit.h b/indra/llwindow/llwindowmacosx_iokit.h new file mode 100644 index 0000000000..a6be2c86ef --- /dev/null +++ b/indra/llwindow/llwindowmacosx_iokit.h @@ -0,0 +1,35 @@ +/** + * @file llwindowmacosx_iokit.h + * @brief IOKit compatibility for macOS deployment target differences + * + * $LicenseInfo:firstyear=2025&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2025, 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 <IOKit/IOKitLib.h> + +// kIOMainPortDefault is the macOS 12+ rename of kIOMasterPortDefault. +#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 120000 +static const mach_port_t kLLIOMainPort = kIOMainPortDefault; +#else +static const mach_port_t kLLIOMainPort = kIOMasterPortDefault; +#endif 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 ad40dea0c3..c98913e8b5 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -37,7 +37,10 @@ #include "llstring.h" #include "lldir.h" #include "llfindlocale.h" +#include "llpreeditor.h" +#include "llsdl.h" +#if LL_LINUX || __FreeBSD__ #ifdef LL_GLIB #include <glib.h> #endif @@ -46,66 +49,39 @@ extern "C" { # include "fontconfig/fontconfig.h" } -#if LL_LINUX || __FreeBSD__ // 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> -# define GLX_GLXEXT_PROTOTYPES 1 -# include <GL/glx.h> -# include <stdio.h> -#endif // LL_LINUX +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdio.h> -extern bool gDebugWindowProc; - -const S32 MAX_NUM_RESOLUTIONS = 200; +#if LL_X11 +LLWindowSDL::X11_DATA LLWindowSDL::sX11Data = {}; +#endif +#if LL_WAYLAND +LLWindowSDL::WAYLAND_DATA LLWindowSDL::sWaylandData = {}; +#endif +#endif // LL_LINUX #if LL_DARWIN - #include <OpenGL/OpenGL.h> -#include <CoreGraphics/CGDirectDisplay.h> +#include <Carbon/Carbon.h> #include <CoreServices/CoreServices.h> - -bool gHiDPISupport = true; - -namespace -{ - struct NativeKeyEventData { - enum EventType { - KEYUNKNOWN, - KEYUP, - KEYDOWN, - KEYCHAR - }; - - EventType mKeyEvent = KEYUNKNOWN; - uint32_t mEventType = 0; - uint32_t mEventModifiers = 0; - uint32_t mEventKeyCode = 0; - uint32_t mEventChars = 0; - uint32_t mEventUnmodChars = 0; - bool mEventRepeat = false; - } *mRawKeyEvent = NULL; -} -// -// LLWindowMacOSX -// +#include <CoreGraphics/CGDisplayConfiguration.h> bool LLWindowSDL::sUseMultGL = false; - #endif -bool hasHIDPI = 0; +bool gHiDPISupport = true; + +const S32 MAX_NUM_RESOLUTIONS = 200; +const S32 DEFAULT_REFRESH_RATE = 60; // // LLWindowSDL // -#if LL_X11 -# include <X11/Xutil.h> -#endif //LL_X11 - #if LL_WINDOWS && !LL_MESA_HEADLESS #pragma comment(lib, "dinput8") #endif @@ -114,44 +90,7 @@ bool hasHIDPI = 0; // set of reasons): Stash a pointer to the LLWindowSDL object here and // maintain in the constructor and destructor. This assumes that there will // be only one object of this class at any time. Currently this is true. -static LLWindowSDL *gWindowImplementation = NULL; - - -void maybe_lock_display(void) -{ - if (gWindowImplementation && gWindowImplementation->Lock_Display) { - gWindowImplementation->Lock_Display(); - } -} - - -void maybe_unlock_display(void) -{ - if (gWindowImplementation && gWindowImplementation->Unlock_Display) { - gWindowImplementation->Unlock_Display(); - } -} - - -#if LL_X11 -// static -Window LLWindowSDL::get_SDL_XWindowID(void) -{ - if (gWindowImplementation) { - return gWindowImplementation->mSDL_XWindowID; - } - return None; -} - -//static -Display* LLWindowSDL::get_SDL_Display(void) -{ - if (gWindowImplementation) { - return gWindowImplementation->mSDL_Display; - } - return NULL; -} -#endif // LL_X11 +static LLWindowSDL *gWindowImplementation = nullptr; LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, @@ -160,36 +99,16 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, bool enable_vsync, bool use_gl, bool ignore_pixel_depth, U32 fsaa_samples) : LLWindow(callbacks, fullscreen, flags), - Lock_Display(NULL), - Unlock_Display(NULL), mGamma(1.0f) + 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 - -#if LL_DARWIN - hasHIDPI = gHiDPISupport; -#endif - - // Ignore use_gl for now, only used for drones on PC - mWindow = NULL; - mContext = {}; - mNeedsResize = false; - mOverrideAspectRatio = 0.f; - mGrabbyKeyFlags = 0; - mReallyCapturedCount = 0; - mHaveInputFocus = -1; - mIsMinimized = -1; - mFSAASamples = fsaa_samples; - -#if LL_X11 - mSDL_XWindowID = None; - mSDL_Display = nullptr; -#endif // LL_X11 // Assume 4:3 aspect ratio until we know better - mOriginalAspectRatio = 1024.0 / 768.0; + mNativeAspectRatio = 1024.f / 768.f; if (title.empty()) mWindowTitle = "Second Life"; @@ -199,6 +118,7 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, // Create the GL context and set it up for windowed or fullscreen, as appropriate. if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) { + gGLManager.initWGL(); gGLManager.initGL(); //start with arrow cursor @@ -210,11 +130,6 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, // Stash an object pointer for OSMessageBox() gWindowImplementation = this; - - mFlashing = false; - - mKeyVirtualKey = 0; - mKeyModifiers = KMOD_NONE; } static SDL_Surface *Load_BMP_Resource(const char *basename) @@ -243,7 +158,7 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; // If the requested width or height is 0, find the best default for the monitor. - if((width == 0) || (height == 0)) + if(width == 0 || height == 0) { // Scan through the list of modes, looking for one which has: // height between 700 and 800 @@ -251,23 +166,22 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) S32 resolutionCount = 0; LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount); - if(resolutionList != NULL) + if(resolutionList != nullptr) { 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; + LL_INFOS() << "createContext: searching for a display mode, original aspect is " << mNativeAspectRatio << LL_ENDL; - for(i=0; i < resolutionCount; i++) + for(S32 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))) + (fabs(aspect - mNativeAspectRatio) < fabs(closestAspect - mNativeAspectRatio))) { LL_INFOS() << " (new closest mode) " << LL_ENDL; @@ -283,7 +197,7 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) } } - if((width == 0) || (height == 0)) + if(width == 0 || height == 0) { // Mode search failed for some reason. Use the old-school default. width = 1024; @@ -293,58 +207,10 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) 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; - - 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_IME_INTERNAL_EDITING,"1"} - }; - - 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_AUDIO,"SDL_INIT_AUDIO", false}, - {SDL_INIT_GAMECONTROLLER,"SDL_INIT_GAMECONTROLLER", false}, - {SDL_INIT_SENSOR,"SDL_INIT_SENSOR", false} - }; - - for( auto subSystem : initList) - { - if( SDL_InitSubSystem( std::get<0>(subSystem) ) < 0 ) - { - LL_WARNS() << "SDL_InitSubSystem for " << std::get<1>(subSystem) << " failed " << SDL_GetError() << LL_ENDL; - - if( std::get<2>(subSystem)) - setupFailure("SDL_Init() failure", "error", OSMB_OK); - - } - } - - SDL_version c_sdl_version; - SDL_VERSION(&c_sdl_version); - LL_INFOS() << "Compiled against SDL " - << int(c_sdl_version.major) << "." - << int(c_sdl_version.minor) << "." - << int(c_sdl_version.patch) << LL_ENDL; - SDL_version r_sdl_version; - SDL_GetVersion(&r_sdl_version); - LL_INFOS() << " Running against SDL " - << int(r_sdl_version.major) << "." - << int(r_sdl_version.minor) << "." - << int(r_sdl_version.patch) << LL_ENDL; if (width == 0) width = 1024; @@ -357,18 +223,6 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b mFullscreen = fullscreen; - int sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; - - if( mFullscreen ) - { - sdlflags |= SDL_WINDOW_FULLSCREEN; - tryFindFullscreenSize( width, height ); - } - - if(hasHIDPI) sdlflags = sdlflags | SDL_WINDOW_ALLOW_HIGHDPI; - - mSDLFlags = sdlflags; - // Setup default backing colors GLint redBits{8}, greenBits{8}, blueBits{8}, alphaBits{8}; GLint depthBits{24}, stencilBits{8}; @@ -379,33 +233,55 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b 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); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GLContextFlag context_flags{}; + if(LLRender::sGLCoreProfile) + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); #if LL_DARWIN - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + context_flags |= SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG; #else - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); #endif - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + } - U32 context_flags = 0; if (gDebugGL) { context_flags |= SDL_GL_CONTEXT_DEBUG_FLAG; } + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, context_flags); SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); - // Create the window - mWindow = SDL_CreateWindow(mWindowTitle.c_str(), x, y, width, height, mSDLFlags); + if(mFullscreen) + { + tryFindFullscreenSize(width, height); + } + + 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); + + mWindow = SDL_CreateWindowWithProperties(props); if (mWindow == nullptr) { 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 // Create the context mContext = SDL_GL_CreateContext(mWindow); @@ -416,53 +292,92 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b return false; } - if (SDL_GL_MakeCurrent(mWindow, mContext) != 0) + if (!SDL_GL_MakeCurrent(mWindow, mContext)) { 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(mFullscreen) + const SDL_DisplayMode* displayMode = SDL_GetCurrentDisplayMode(SDL_GetDisplayForWindow(mWindow)); + if(displayMode) { - if (mWindow) + mRefreshRate = ll_round(displayMode->refresh_rate); + mNativeAspectRatio = ((F32)displayMode->w) / ((F32)displayMode->h); + if(mFullscreen) { - mFullscreen = true; - /* - mFullscreenWidth = mSurface->w; - mFullscreenHeight = mSurface->h; - */ - SDL_GetWindowSize(mWindow, &mFullscreenWidth, &mFullscreenHeight); - mFullscreenRefresh = -1; + mFullscreenWidth = displayMode->w; + mFullscreenHeight = displayMode->h; + mFullscreenRefresh = ll_round(displayMode->refresh_rate); LL_INFOS() << "Running at " << mFullscreenWidth - << "x" << mFullscreenHeight - << " @ " << mFullscreenRefresh - << LL_ENDL; + << "x" << mFullscreenHeight + << " @ " << mFullscreenRefresh + << LL_ENDL; } - else + } + 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 { - LL_WARNS() << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << LL_ENDL; - // No fullscreen support - mFullscreen = false; - mFullscreenWidth = -1; - mFullscreenHeight = -1; + SDL_GetWindowSize(mWindow, &mFullscreenWidth, &mFullscreenHeight); mFullscreenRefresh = -1; + } + } + + if(mRefreshRate == 0) // We failed to get a valid refresh rate above + { + mRefreshRate = DEFAULT_REFRESH_RATE; + } + + /* Grab the window manager specific information */ +#if LL_LINUX || __FreeBSD__ + if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) + { + LL_INFOS() << "Running under X11" << LL_ENDL; + mServerProtocol = X11; + + 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) + { - std::string error = llformat("Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); - OSMessageBox(error, "Error", OSMB_OK); - return false; } +#endif + + gGLManager.initGLX(); } - else + else if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) { - if (!mWindow) + LL_INFOS() << "Running under Wayland" << LL_ENDL; + mServerProtocol = Wayland; + + gGLManager.mIsWayland = true; + +#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; + } +#endif + + gGLManager.initEGL(); + + // If set (XWayland) remove DISPLAY, this will prompt dullahan to also use Wayland + if(getenv("DISPLAY")) + { + unsetenv("DISPLAY"); } } +#endif SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &redBits); SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &greenBits); @@ -480,13 +395,8 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b 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) { -#if 0 - close(); setupFailure( "Second Life requires True Color (32-bit) to run in a window.\n" "Please go to Control Panels -> Display -> Settings and\n" @@ -496,7 +406,6 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b "Error", OSMB_OK); return false; -#endif } LL_PROFILER_GPU_CONTEXT; @@ -504,104 +413,87 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b // 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) { SDL_SetWindowIcon(mWindow, bmpsurface); - SDL_FreeSurface(bmpsurface); - bmpsurface = NULL; + SDL_DestroySurface(bmpsurface); + bmpsurface = nullptr; } -#if LL_X11 - /* Grab the window manager specific information */ - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - if ( SDL_GetWindowWMInfo(mWindow, &info) ) - { - /* Save the information for later use */ - if ( info.subsystem == SDL_SYSWM_X11 ) - { - mSDL_Display = info.info.x11.display; - mSDL_XWindowID = info.info.x11.window; - } - else - { - LL_WARNS() << "We're not running under X11? Wild." - << LL_ENDL; - } - } - else - { - LL_WARNS() << "We're not running under any known WM. Wild." - << LL_ENDL; - } -#endif // LL_X11 + SDL_StartTextInput(mWindow); + return true; +} -# if LL_X11 - PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC queryInteger; - queryInteger = (PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC)glXGetProcAddressARB((const GLubyte *)"glXQueryCurrentRendererIntegerMESA"); - unsigned int vram_megabytes = 0; - queryInteger(GLX_RENDERER_VIDEO_MEMORY_MESA, &vram_megabytes); - if (!vram_megabytes) - { - glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, (int *)&vram_megabytes); - vram_megabytes /= 1024; - } - if (!vram_megabytes) - { - glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, (int *)&vram_megabytes); - vram_megabytes /= 1024; - } - gGLManager.mVRAM = vram_megabytes; -#elif LL_DARWIN - CGLRendererInfoObj info = 0; - GLint vram_megabytes = 0; - int num_renderers = 0; - auto err = CGLQueryRendererInfo(CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay), &info, &num_renderers); - if (!err) +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) { - CGLDescribeRenderer(info, 0, kCGLRPVideoMemoryMegabytes, &vram_megabytes); - CGLDestroyRendererInfo(info); + 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) { - vram_megabytes = 256; + LL_WARNS() << "Creating shared OpenGL context failed!" << LL_ENDL; + SDL_DestroyWindow(osr_window); + return nullptr; } - gGLManager.mVRAM = vram_megabytes; -# endif - SDL_StartTextInput(); - //make sure multisampling is disabled by default -#if GL_VERSION_1_3 - glDisable(GL_MULTISAMPLE_ARB); -#endif - // Don't need to get the current gamma, since there's a call that restores it to the system defaults. - return true; -} - -void* LLWindowSDL::createSharedContext() -{ - SDL_GLContext pContext = SDL_GL_CreateContext(mWindow); - if (pContext) { - LL_DEBUGS() << "Creating shared OpenGL context successful!" << LL_ENDL; - return (void*)pContext; + LLMutexLock osr_lock(&mOSRMutex); + mOSRContexts.emplace(pContext, osr_window); } - LL_WARNS() << "Creating shared OpenGL context failed!" << LL_ENDL; - return nullptr; + LL_DEBUGS() << "Creating shared OpenGL context successful!" << LL_ENDL; + return (void*)pContext; } void LLWindowSDL::makeContextCurrent(void* contextPtr) { - SDL_GL_MakeCurrent(mWindow, 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; } void LLWindowSDL::destroySharedContext(void* contextPtr) { - SDL_GL_DeleteContext(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) @@ -610,13 +502,11 @@ void LLWindowSDL::toggleVSync(bool enable_vsync) { LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL; SDL_GL_SetSwapInterval(0); - SDL_SetHintWithPriority(SDL_HINT_RENDER_VSYNC,"0",SDL_HINT_OVERRIDE); } else { LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL; SDL_GL_SetSwapInterval(1); - SDL_SetHintWithPriority(SDL_HINT_RENDER_VSYNC,"1",SDL_HINT_OVERRIDE); } } @@ -634,6 +524,7 @@ bool LLWindowSDL::switchContext(bool fullscreen, const LLCoordScreen &size, bool result = createContext(0, 0, size.mX, size.mY, 32, fullscreen, enable_vsync); if (result) { + gGLManager.initWGL(); gGLManager.initGL(); //start with arrow cursor @@ -651,27 +542,29 @@ void LLWindowSDL::destroyContext() { LL_INFOS() << "destroyContext begins" << LL_ENDL; + { + LLMutexLock osr_lock(&mOSRMutex); + for(SDL_Window* pWindow : mDeadOSRWindows) + { + SDL_DestroyWindow(pWindow); + } + mDeadOSRWindows.clear(); + } + // Stop unicode input - SDL_StopTextInput(); + SDL_StopTextInput(mWindow); // Clean up remaining GL state before blowing away window LL_INFOS() << "shutdownGL begins" << LL_ENDL; gGLManager.shutdownGL(); -#if LL_X11 - mSDL_Display = NULL; - mSDL_XWindowID = None; - Lock_Display = NULL; - Unlock_Display = NULL; -#endif // LL_X11 - LL_INFOS() << "Destroying SDL cursors" << LL_ENDL; quitCursors(); if (mContext) { LL_INFOS() << "Destroying SDL GL Context" << LL_ENDL; - SDL_GL_DeleteContext(mContext); + SDL_GL_DestroyContext(mContext); mContext = nullptr; } else @@ -690,21 +583,15 @@ void LLWindowSDL::destroyContext() LL_INFOS() << "SDL Window already destroyed" << LL_ENDL; } LL_INFOS() << "destroyContext end" << LL_ENDL; - - LL_INFOS() << "SDL_QuitSS/VID begins" << LL_ENDL; - SDL_QuitSubSystem(SDL_INIT_VIDEO); // *FIX: this might be risky... } LLWindowSDL::~LLWindowSDL() { destroyContext(); - if(mSupportedResolutions != NULL) - { - delete []mSupportedResolutions; - } + delete[] mSupportedResolutions; - gWindowImplementation = NULL; + gWindowImplementation = nullptr; } @@ -713,6 +600,7 @@ void LLWindowSDL::show() if (mWindow) { SDL_ShowWindow(mWindow); + SDL_RaiseWindow(mWindow); } } @@ -724,7 +612,6 @@ void LLWindowSDL::hide() } } -//virtual void LLWindowSDL::minimize() { if (mWindow) @@ -733,7 +620,6 @@ void LLWindowSDL::minimize() } } -//virtual void LLWindowSDL::restore() { if (mWindow) @@ -746,12 +632,6 @@ void LLWindowSDL::restore() // 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(); @@ -761,18 +641,18 @@ void LLWindowSDL::close() bool LLWindowSDL::isValid() { - return (mWindow != NULL); + return mWindow != nullptr; } bool LLWindowSDL::getVisible() { - bool result = false; + bool result = true; if (mWindow) { - Uint32 flags = SDL_GetWindowFlags(mWindow); - if (flags & SDL_WINDOW_SHOWN) + SDL_WindowFlags flags = SDL_GetWindowFlags(mWindow); + if (flags & SDL_WINDOW_HIDDEN) { - result = true; + result = false; } } return result; @@ -783,7 +663,7 @@ bool LLWindowSDL::getMinimized() bool result = false; if (mWindow) { - Uint32 flags = SDL_GetWindowFlags(mWindow); + SDL_WindowFlags flags = SDL_GetWindowFlags(mWindow); if (flags & SDL_WINDOW_MINIMIZED) { result = true; @@ -797,7 +677,7 @@ bool LLWindowSDL::getMaximized() bool result = false; if (mWindow) { - Uint32 flags = SDL_GetWindowFlags(mWindow); + SDL_WindowFlags flags = SDL_GetWindowFlags(mWindow); if (flags & SDL_WINDOW_MAXIMIZED) { result = true; @@ -817,11 +697,6 @@ bool LLWindowSDL::maximize() return false; } -bool LLWindowSDL::getFullscreen() -{ - return mFullscreen; -} - bool LLWindowSDL::getPosition(LLCoordScreen *position) { if (mWindow) @@ -836,30 +711,22 @@ bool LLWindowSDL::getSize(LLCoordScreen *size) { if (mWindow) { - /* - if(hasHIDPI) - SDL_GL_GetDrawableSize(mWindow, &size->mX, &size->mY); - else - */ SDL_GetWindowSize(mWindow, &size->mX, &size->mY); - return (true); + return true; } - return (false); + return false; } bool LLWindowSDL::getSize(LLCoordWindow *size) { if (mWindow) { - if(hasHIDPI) - SDL_GL_GetDrawableSize(mWindow, &size->mX, &size->mY); - else - SDL_GetWindowSize(mWindow, &size->mX, &size->mY); - return (true); + SDL_GetWindowSizeInPixels(mWindow, &size->mX, &size->mY); + return true; } - return (false); + return false; } bool LLWindowSDL::setPosition(const LLCoordScreen position) @@ -878,21 +745,12 @@ template< typename T > bool setSizeImpl( const T& newSize, SDL_Window *pWin ) if( !pWin ) return false; - auto nFlags = SDL_GetWindowFlags( pWin ); - - if( nFlags & SDL_WINDOW_MAXIMIZED ) - SDL_RestoreWindow( pWin ); + SDL_WindowFlags winFlags = SDL_GetWindowFlags(pWin); + if( winFlags & SDL_WINDOW_MAXIMIZED) + SDL_RestoreWindow(pWin); - SDL_SetWindowSize( pWin, newSize.mX, newSize.mY ); - SDL_Event event; - event.type = SDL_WINDOWEVENT; - event.window.event = SDL_WINDOWEVENT_RESIZED; - event.window.windowID = SDL_GetWindowID( pWin ); - event.window.data1 = newSize.mX; - event.window.data2 = newSize.mY; - SDL_PushEvent( &event ); - + SDL_SetWindowSize(pWin, newSize.mX, newSize.mY); return true; } @@ -933,12 +791,6 @@ F32 LLWindowSDL::getGamma() bool LLWindowSDL::restoreGamma() { - if (mWindow) - { - Uint16 ramp[256]; - SDL_CalculateGammaRamp(1.f, ramp); - SDL_SetWindowGammaRamp(mWindow, ramp, ramp, ramp); - } return true; } @@ -946,14 +798,10 @@ bool LLWindowSDL::setGamma(const F32 gamma) { if (mWindow) { - Uint16 ramp[256]; - mGamma = gamma; - if (mGamma == 0) mGamma = 0.1f; + if (mGamma == 0) + mGamma = 0.1f; mGamma = 1.f / mGamma; - - SDL_CalculateGammaRamp(mGamma, ramp); - SDL_SetWindowGammaRamp(mWindow, ramp, ramp, ramp); } return true; } @@ -966,7 +814,10 @@ bool LLWindowSDL::isCursorHidden() // Constrains the mouse to the window. void LLWindowSDL::setMouseClipping(bool b) { - //SDL_WM_GrabInput(b ? SDL_GRAB_ON : SDL_GRAB_OFF); + if (mWindow) + { + SDL_SetWindowMouseGrab(mWindow, b); + } } // virtual @@ -982,29 +833,15 @@ void LLWindowSDL::setMinSize(U32 min_width, U32 min_height, bool enforce_immedia 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. - + /* if (mFullscreen) { - SDL_WarpMouseGlobal(screen_pos.mX, screen_pos.mY); - return result; + SDL_WarpMouseGlobal((F32)position.mX, (F32)position.mY); + return true; } - - SDL_WarpMouseInWindow(mWindow, screen_pos.mX, screen_pos.mY); - - //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; - - return result; + */ + SDL_WarpMouseInWindow(mWindow, (F32)position.mX, (F32)position.mY); + return true; } bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) @@ -1012,46 +849,34 @@ bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) //Point cursor_point; LLCoordScreen screen_pos; - 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::getSystemUISize() -{ - if(hasHIDPI) return 2.0f; - else return 1.f; -} - F32 LLWindowSDL::getNativeAspectRatio() { - // MBW -- there are a couple of bad assumptions here. One is that the display list won't include - // ridiculous resolutions nobody would ever use. The other is that the list is in order. - - // New assumptions: - // - pixels are square (the only reasonable choice, really) - // - The user runs their display at a native resolution, so the resolution of the display - // when the app is launched has an aspect ratio that matches the monitor. - - //RN: actually, the assumption that there are no ridiculous resolutions (above the display's native capabilities) has - // been born out in my experience. - // Pixels are often not square (just ask the people who run their LCDs at 1024x768 or 800x600 when running fullscreen, like me) - // The ordering of display list is a blind assumption though, so we should check for max values - // Things might be different on the Mac though, so I'll defer to MBW - - // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution - // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. - if (mOverrideAspectRatio > 0.f) { return mOverrideAspectRatio; } + else if (mNativeAspectRatio > 0.f) + { + // we grabbed this value at startup, based on the user's desktop settings + return mNativeAspectRatio; + } - return mOriginalAspectRatio; + // 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); } F32 LLWindowSDL::getPixelAspectRatio() @@ -1074,61 +899,21 @@ 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_SetWindowFullscreen( mWindow, 0 ); - } - } - } - -#if LL_X11 - if (mSDL_Display) - { - // Everything that we/SDL asked for should happen before we - // potentially hand control over to GTK. - maybe_lock_display(); - XSync(mSDL_Display, False); - maybe_unlock_display(); + if (mFullscreen && mWindow ) + SDL_SetWindowFullscreen( mWindow, 0 ); } -#endif // LL_X11 - - maybe_lock_display(); } void LLWindowSDL::afterDialog() { - bool running_x11 = false; -#if LL_X11 - running_x11 = (mSDL_XWindowID != None); -#endif //LL_X11 - LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; - maybe_unlock_display(); - - if (mFullscreen) - { - // need to restore fullscreen mode after dialog - only works - // in X11 - if (running_x11 && mWindow) - { - SDL_SetWindowFullscreen( mWindow, 0 ); - } - } + if (mFullscreen && mWindow ) + SDL_SetWindowFullscreen( mWindow, 0 ); } void LLWindowSDL::flashIcon(F32 seconds) @@ -1145,9 +930,18 @@ void LLWindowSDL::flashIcon(F32 seconds) mFlashing = true; } +void LLWindowSDL::maybeStopFlashIcon() +{ + if (mFlashing && mFlashTimer.hasExpired()) + { + mFlashing = false; + SDL_FlashWindow( mWindow, SDL_FLASH_CANCEL ); + } +} + bool LLWindowSDL::isClipboardTextAvailable() { - return SDL_HasClipboardText() == SDL_TRUE; + return SDL_HasClipboardText(); } bool LLWindowSDL::pasteTextFromClipboard(LLWString &dst) @@ -1168,12 +962,12 @@ bool LLWindowSDL::pasteTextFromClipboard(LLWString &dst) bool LLWindowSDL::copyTextToClipboard(const LLWString& text) { const std::string utf8 = wstring_to_utf8str(text); - return SDL_SetClipboardText(utf8.c_str()) == 0; // success == 0 + return SDL_SetClipboardText(utf8.c_str()); } bool LLWindowSDL::isPrimaryTextAvailable() { - return SDL_HasPrimarySelectionText() == SDL_TRUE; + return SDL_HasPrimarySelectionText(); } bool LLWindowSDL::pasteTextFromPrimary(LLWString &dst) @@ -1194,7 +988,7 @@ bool LLWindowSDL::pasteTextFromPrimary(LLWString &dst) bool LLWindowSDL::copyTextToPrimary(const LLWString& text) { const std::string utf8 = wstring_to_utf8str(text); - return SDL_SetPrimarySelectionText(utf8.c_str()) == 0; // success == 0 + return SDL_SetPrimarySelectionText(utf8.c_str()); } LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions) @@ -1204,32 +998,29 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; mNumSupportedResolutions = 0; - // <FS:ND> Use display no from mWindow/mSurface here? - int max = SDL_GetNumDisplayModes(0); - max = llclamp( max, 0, MAX_NUM_RESOLUTIONS ); - - for( int i =0; i < max; ++i ) - { - SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 }; - if (SDL_GetDisplayMode( 0 , i, &mode) != 0) - { - continue; - } - - int w = mode.w; - int h = mode.h; - if ((w >= 800) && (h >= 600)) - { - // make sure we don't add the same resolution multiple times! - if ( (mNumSupportedResolutions == 0) || - ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) && - (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) ) + 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)) { - mSupportedResolutions[mNumSupportedResolutions].mWidth = w; - mSupportedResolutions[mNumSupportedResolutions].mHeight = h; - mNumSupportedResolutions++; + // make sure we don't add the same resolution multiple times! + if ( (mNumSupportedResolutions == 0) || + ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) && + (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) ) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = w; + mSupportedResolutions[mNumSupportedResolutions].mHeight = h; + mNumSupportedResolutions++; + } } } + SDL_free(modes); } } @@ -1237,15 +1028,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; - int h; - SDL_GetWindowSize(mWindow, nullptr, &h); - to->mY = 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; } @@ -1255,10 +1073,15 @@ bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) if (!to) return false; - to->mX = from.mX; - int h; - SDL_GetWindowSize(mWindow, nullptr, &h); - to->mY = 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; } @@ -1271,7 +1094,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) @@ -1282,26 +1105,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); } @@ -1332,13 +1155,13 @@ bool LLWindowSDL::SDLReallyCaptureInput(bool capture) } bool newGrab = wantGrab; - if (!mFullscreen) /* only bother if we're windowed anyway */ { int result; - if (wantGrab == true) + if (wantGrab) { - result = SDL_CaptureMouse(SDL_TRUE); + // LL_INFOS() << "X11 POINTER GRABBY" << LL_ENDL; + result = SDL_SetWindowMouseGrab(mWindow, true); if (0 == result) newGrab = true; else @@ -1347,9 +1170,10 @@ bool LLWindowSDL::SDLReallyCaptureInput(bool capture) else { newGrab = false; - result = SDL_CaptureMouse(SDL_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 == newGrab; @@ -1396,354 +1220,260 @@ U32 LLWindowSDL::SDLCheckGrabbyKeys(U32 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 { - LL_WARNS() << "RSS size grew by " << (this_rss_size - last_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + if (event.button.clicks == 2) + mCallbacks->handleDoubleClick(this, openGlCoord, mask); + else + mCallbacks->handleMouseDown(this, openGlCoord, mask); + } + else if (event.button.button == SDL_BUTTON_RIGHT) + { + 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 -} - - -// virtual -void LLWindowSDL::processMiscNativeEvents() -{ -#if LL_GLIB - // Pump until we've nothing left to do or passed 1/15th of a - // second pumping for this frame. - static LLTimer pump_timer; - pump_timer.reset(); - pump_timer.setTimerExpirySec(1.0f / 15.0f); - do - { - g_main_context_iteration(g_main_context_default(), false); - } while( g_main_context_pending(g_main_context_default()) && !pump_timer.hasExpired()); -#endif - // hack - doesn't belong here - but this is just for debugging - if (getenv("LL_DEBUG_BLOAT")) - { - check_vm_bloat(); - } -} - -void LLWindowSDL::gatherInput() -{ - SDL_Event event; - - // Handle all outstanding SDL events - while (SDL_PollEvent(&event)) - { - switch (event.type) + case SDL_EVENT_MOUSE_BUTTON_UP: { - case SDL_MOUSEWHEEL: + 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.wheel.y != 0 ) - { - mCallbacks->handleScrollWheel(this, -event.wheel.y); - } - if (event.wheel.x != 0) - { - mCallbacks->handleScrollHWheel(this, -event.wheel.x); - } - break; + mCallbacks->handleMouseUp(this, openGlCoord, mask); } - - case SDL_MOUSEMOTION: + else if (event.button.button == SDL_BUTTON_RIGHT) // right { - LLCoordWindow winCoord(event.motion.x, event.motion.y); - LLCoordGL openGlCoord; - convertCoords(winCoord, &openGlCoord); - - openGlCoord.mX = openGlCoord.mX * getSystemUISize(); - openGlCoord.mY = openGlCoord.mY * getSystemUISize(); - - //LL_INFOS() << "SDL_MOUSEMOTION " << event.button.x << " " << event.button.y << " gl " << openGlCoord.mX << " " << openGlCoord.mY << LL_ENDL; - - MASK mask = gKeyboard->currentMask(true); - mCallbacks->handleMouseMove(this, openGlCoord, mask); - break; + mCallbacks->handleRightMouseUp(this, openGlCoord, mask); } - - case SDL_TEXTINPUT: + else if (event.button.button == SDL_BUTTON_MIDDLE) // middle { - auto string = utf8str_to_utf16str( event.text.text ); - mKeyModifiers = gKeyboard->currentMask( false ); - mInputType = "textinput"; - for( auto key: string ) - { - mKeyVirtualKey = key; - - if( (MASK_CONTROL|MASK_ALT)&mKeyModifiers ) - gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers ); - else - handleUnicodeUTF16( key, mKeyModifiers ); - } - break; + mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask); + } + else + { + mCallbacks->handleOtherMouseUp(this, openGlCoord, mask, event.button.button); } - case SDL_KEYDOWN: - mKeyVirtualKey = event.key.keysym.sym; - mKeyModifiers = event.key.keysym.mod; - mInputType = "keydown"; - - // treat all possible Enter/Return keys the same - if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) - { - mKeyVirtualKey = SDLK_RETURN; - } - - gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers ); - - // <FS:ND> Slightly hacky :| To make the viewer honor enter (eg to accept form input) we've to not only send handleKeyDown but also send a - // invoke handleUnicodeUTF16 in case the user hits return. - // Note that we cannot blindly use handleUnicodeUTF16 for each SDL_KEYDOWN. Doing so will create bogus keyboard input (like % for cursor left). - if( mKeyVirtualKey == SDLK_RETURN ) - { - // fix return key not working when capslock, scrolllock or numlock are enabled - mKeyModifiers &= (~(KMOD_NUM | KMOD_CAPS | KMOD_MODE | KMOD_SCROLL)); - handleUnicodeUTF16( mKeyVirtualKey, mKeyModifiers ); - } - - // part of the fix for SL-13243 - if (SDLCheckGrabbyKeys(event.key.keysym.sym, true) != 0) - SDLReallyCaptureInput(true); - - break; - - case SDL_KEYUP: - mKeyVirtualKey = event.key.keysym.sym; - mKeyModifiers = event.key.keysym.mod; - mInputType = "keyup"; + break; + } - // treat all possible Enter/Return keys the same - if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) - { - mKeyVirtualKey = SDLK_RETURN; - } + case SDL_EVENT_KEY_DOWN: + { + mKeyVirtualKey = event.key.key; + mKeyModifiers = event.key.mod; - if (SDLCheckGrabbyKeys(mKeyVirtualKey, false) == 0) - SDLReallyCaptureInput(false); // part of the fix for SL-13243 + if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) + { + mKeyVirtualKey = SDLK_RETURN; + } - gKeyboard->handleKeyUp(mKeyVirtualKey,mKeyModifiers); - break; + gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers); - case SDL_MOUSEBUTTONDOWN: + if (mKeyVirtualKey == SDLK_RETURN) { - LLCoordWindow winCoord(event.button.x, event.button.y); - LLCoordGL openGlCoord; - convertCoords(winCoord, &openGlCoord); - - openGlCoord.mX *= getSystemUISize(); - openGlCoord.mY *= getSystemUISize(); + // 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)); + } - MASK mask = gKeyboard->currentMask(true); + // part of the fix for SL-13243 + if (SDLCheckGrabbyKeys(mKeyVirtualKey, true) != 0) + SDLReallyCaptureInput(true); + break; + } - 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) // right - { - mCallbacks->handleRightMouseDown(this, openGlCoord, mask); - } - else if (event.button.button == SDL_BUTTON_MIDDLE) // middle - { - mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); - } - else - { - mCallbacks->handleOtherMouseDown(this, openGlCoord, mask, event.button.button); - } + case SDL_EVENT_KEY_UP: + { + mKeyVirtualKey = event.key.key; + mKeyModifiers = event.key.mod; - break; + if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) + { + mKeyVirtualKey = SDLK_RETURN; } - case SDL_MOUSEBUTTONUP: - { - LLCoordWindow winCoord(event.button.x, event.button.y); - LLCoordGL openGlCoord; - convertCoords(winCoord, &openGlCoord); + gKeyboard->handleKeyUp(mKeyVirtualKey, mKeyModifiers); + if (SDLCheckGrabbyKeys(mKeyVirtualKey, false) == 0) + SDLReallyCaptureInput(false); // part of the fix for SL-13243 + break; + } - openGlCoord.mX *= getSystemUISize(); - openGlCoord.mY *= getSystemUISize(); + case SDL_EVENT_TEXT_INPUT: + { + auto string = utf8str_to_wstring(event.text.text); + MASK current_mask = gKeyboard->currentMask(false); + for (auto key : string) + { + mKeyVirtualKey = key; + mCallbacks->handleUnicodeChar(key, current_mask); + } + break; + } - MASK mask = gKeyboard->currentMask(true); + case SDL_EVENT_WINDOW_EXPOSED: + { + mCallbacks->handlePaint(this, 0, 0, 0, 0); + break; + } - 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); - } + 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; - break; + 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) + { + mRefreshRate = ll_round(displayMode->refresh_rate); + mNativeAspectRatio = ((F32)displayMode->w) / ((F32)displayMode->h); } - - case SDL_WINDOWEVENT: + 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)) { - switch(event.window.event) - { - //case SDL_WINDOWEVENT_SIZE_CHANGED: <FS:ND> SDL_WINDOWEVENT_SIZE_CHANGED is followed by SDL_WINDOWEVENT_RESIZED, so handling one shall be enough - case SDL_WINDOWEVENT_RESIZED: - { - LL_INFOS() << "Handling a resize event: " << event.window.data1 << "x" << event.window.data2 << LL_ENDL; - S32 width = llmax(event.window.data1, (S32)mMinWindowWidth); - S32 height = llmax(event.window.data2, (S32)mMinWindowHeight); - - mCallbacks->handleResize(this, width * getSystemUISize(), height * getSystemUISize()); - break; - } - case SDL_WINDOWEVENT_LEAVE: - mCallbacks->handleMouseLeave(this); - break; - case SDL_WINDOWEVENT_FOCUS_GAINED: - mCallbacks->handleFocus(this); - break; - case SDL_WINDOWEVENT_FOCUS_LOST: - mCallbacks->handleFocusLost(this); - break; - case SDL_WINDOWEVENT_EXPOSED: - case SDL_WINDOWEVENT_SHOWN: - case SDL_WINDOWEVENT_HIDDEN: - case SDL_WINDOWEVENT_MINIMIZED: - case SDL_WINDOWEVENT_MAXIMIZED: - case SDL_WINDOWEVENT_RESTORED: - { - Uint32 flags = SDL_GetWindowFlags(mWindow); - bool minimized = (flags & SDL_WINDOW_MINIMIZED); - bool hidden = (flags & SDL_WINDOW_HIDDEN); - - mCallbacks->handleActivate(this, !minimized || !hidden); - LL_INFOS() << "SDL deiconification state switched to " << minimized << LL_ENDL; - break; - } - } - break; + // Get the app to initiate cleanup. + mCallbacks->handleQuit(this); + // The app is responsible for calling destroyWindow when done with GL } - 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; +} - // 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; - } +// 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) @@ -1758,20 +1488,31 @@ 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, + 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, - 32, - SDL_SwapLE32(0xFFU), - SDL_SwapLE32(0xFF00U), - SDL_SwapLE32(0xFF0000U), - SDL_SwapLE32(0xFF000000U)); - SDL_FillRect(cursurface, NULL, SDL_SwapLE32(0x00000000U)); + 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; @@ -1788,7 +1529,7 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty U8 *pixelp = ((U8*)cursurface->pixels) + cursurface->pitch * i - + j*cursurface->format->BytesPerPixel; + + j*pix_format_details->bytes_per_pixel; U8 srcred = pixelp[0]; U8 srcgreen = pixelp[1]; U8 srcblue = pixelp[2]; @@ -1811,8 +1552,8 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty } 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; } @@ -1845,28 +1586,28 @@ void LLWindowSDL::updateCursor() 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] = 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] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); + 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_HAND); - mSDLCursors[UI_CURSOR_IBEAM] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); + 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_SIZENWSE); - mSDLCursors[UI_CURSOR_SIZENESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); - mSDLCursors[UI_CURSOR_SIZEWE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); - mSDLCursors[UI_CURSOR_SIZENS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); - mSDLCursors[UI_CURSOR_SIZEALL] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL); - mSDLCursors[UI_CURSOR_NO] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO); - mSDLCursors[UI_CURSOR_WORKING] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAITARROW); + 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); @@ -1903,23 +1644,24 @@ void LLWindowSDL::initCursors() 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; } } @@ -1948,7 +1690,7 @@ void LLWindowSDL::hideCursor() // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; mCursorHidden = true; mHideCursorPermanent = true; - SDL_ShowCursor(SDL_DISABLE); + SDL_HideCursor(); } else { @@ -1963,7 +1705,7 @@ void LLWindowSDL::showCursor() // LL_INFOS() << "showCursor: showing" << LL_ENDL; mCursorHidden = false; mHideCursorPermanent = false; - SDL_ShowCursor(SDL_ENABLE); + SDL_ShowCursor(); } else { @@ -2039,37 +1781,28 @@ S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 typ break; } + if(gWindowImplementation != nullptr) + gWindowImplementation->beforeDialog(); + int btn{0}; - if( 0 == SDL_ShowMessageBox( &oData, &btn ) ) + if(SDL_ShowMessageBox( &oData, &btn )) + { + if(gWindowImplementation != nullptr) + gWindowImplementation->afterDialog(); return btn; + } + + if(gWindowImplementation != nullptr) + gWindowImplementation->afterDialog(); + return OSBTN_CANCEL; } bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) { - return (false); + return false; } -#if LL_DARWIN -LLSD LLWindowSDL::getNativeKeyData() -{ - LLSD result = LLSD::emptyMap(); - - if(mRawKeyEvent) - { - result["event_type"] = LLSD::Integer(mRawKeyEvent->mEventType); - result["event_modifiers"] = LLSD::Integer(mRawKeyEvent->mEventModifiers); - result["event_keycode"] = LLSD::Integer(mRawKeyEvent->mEventKeyCode); - result["event_chars"] = (mRawKeyEvent->mEventChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventChars)) : LLSD(); - result["event_umodchars"] = (mRawKeyEvent->mEventUnmodChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventUnmodChars)) : LLSD(); - result["event_isrepeat"] = LLSD::Boolean(mRawKeyEvent->mEventRepeat); - } - - LL_DEBUGS() << "native key data is: " << result << LL_ENDL; - - return result; -} -#else /* 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 @@ -2084,23 +1817,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["virtual_key"] = (S32)mKeyVirtualKey; - result["virtual_key_win"] = (S32)LLKeyboardSDL::mapSDL2toWin( mKeyVirtualKey ); + result["virtual_key_win"] = (S32)LLKeyboardSDL::mapSDLtoWin( mKeyVirtualKey ); result["modifiers"] = (S32)modifiers; - result["input_type"] = mInputType; return result; } -#endif // LL_DARWIN // Open a URL with the user's default web browser. // Must begin with protocol identifier. @@ -2125,7 +1856,7 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) LL_INFOS() << "spawn_web_browser: " << escaped_url << LL_ENDL; - if (SDL_OpenURL(escaped_url.c_str()) != 0) + if (!SDL_OpenURL(escaped_url.c_str())) { LL_WARNS() << "spawn_web_browser failed with error: " << SDL_GetError() << LL_ENDL; } @@ -2133,9 +1864,18 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) LL_INFOS() << "spawn_web_browser returning." << LL_ENDL; } -void *LLWindowSDL::getPlatformWindow() +void* LLWindowSDL::getPlatformWindow() { - return NULL; + void* ret = nullptr; + if (mWindow) + { +#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 + } + return ret; } void LLWindowSDL::bringToFront() @@ -2152,102 +1892,64 @@ void LLWindowSDL::bringToFront() //static std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() { - // Use libfontconfig to find us a nice ordered list of fallback fonts - // specific to this system. - std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf"); - const int max_font_count_cutoff = 40; // fonts are expensive in the current system, don't enumerate an arbitrary number of them - // Our 'ideal' font properties which define the sorting results. - // slant=0 means Roman, index=0 means the first face in a font file - // (the one we actually use), weight=80 means medium weight, - // spacing=0 means proportional spacing. - std::string sort_order("slant=0:index=0:weight=80:spacing=0"); - // elide_unicode_coverage removes fonts from the list whose unicode - // range is covered by fonts earlier in the list. This usually - // removes ~90% of the fonts as redundant (which is great because - // the font list can be huge), but might unnecessarily reduce the - // renderable range if for some reason our FreeType actually fails - // to use some of the fonts we want it to. - const bool elide_unicode_coverage = true; - std::vector<std::string> rtns; - FcFontSet *fs = NULL; - FcPattern *sortpat = NULL; - - LL_INFOS() << "Getting system font list from FontConfig..." << LL_ENDL; + // Lazy-loaded fonts, seeded with fonts.xml + return std::vector<std::string>(); +} - // If the user has a system-wide language preference, then favor - // fonts from that language group. This doesn't affect the types - // of languages that can be displayed, but ensures that their - // preferred language is rendered from a single consistent font where - // possible. - FL_Locale *locale = NULL; - FL_Success success = FL_FindLocale(&locale, FL_MESSAGES); - if (success != 0) +LLFontFallbackMatch LLWindowSDL::findFallbackFontForChar(llwchar wch) +{ + LLFontFallbackMatch result; +#if LL_LINUX || __FreeBSD__ + // FcInit() is idempotent, but this runs per missing codepoint, so only + // attempt initialization once. + static bool fc_ready = FcInit(); + if (!fc_ready) { - if (success >= 2 && locale->lang) // confident! - { - LL_INFOS("AppInit") << "Language " << locale->lang << LL_ENDL; - LL_INFOS("AppInit") << "Location " << locale->country << LL_ENDL; - LL_INFOS("AppInit") << "Variant " << locale->variant << LL_ENDL; - - LL_INFOS() << "Preferring fonts of language: " - << locale->lang - << LL_ENDL; - sort_order = "lang=" + std::string(locale->lang) + ":" - + sort_order; - } + LL_WARNS_ONCE() << "FontConfig failed to initialize." << LL_ENDL; + return result; } - FL_FreeLocale(&locale); - if (!FcInit()) + // Ask FontConfig for the best font covering this codepoint. + FcCharSet* charset = FcCharSetCreate(); + FcPattern* pat = FcPatternCreate(); + if (!charset || !pat) { - LL_WARNS() << "FontConfig failed to initialize." << LL_ENDL; - rtns.push_back(final_fallback); - return rtns; + if (charset) FcCharSetDestroy(charset); + if (pat) FcPatternDestroy(pat); + return result; } - sortpat = FcNameParse((FcChar8*) sort_order.c_str()); - if (sortpat) - { - // Sort the list of system fonts from most-to-least-desirable. - FcResult result; - fs = FcFontSort(NULL, sortpat, elide_unicode_coverage, - NULL, &result); - FcPatternDestroy(sortpat); - } + FcCharSetAddChar(charset, (FcChar32)wch); + + FcPatternAddCharSet(pat, FC_CHARSET, charset); + FcPatternAddBool(pat, FC_SCALABLE, FcTrue); + + FcConfigSubstitute(nullptr, pat, FcMatchPattern); + FcDefaultSubstitute(pat); - int found_font_count = 0; - if (fs) + FcResult fc_result; + FcPattern* match = FcFontMatch(nullptr, pat, &fc_result); + if (match) { - // Get the full pathnames to the fonts, where available, - // which is what we really want. - found_font_count = fs->nfont; - for (int i=0; i<fs->nfont; ++i) + FcChar8* filename = nullptr; + if (FcResultMatch == FcPatternGetString(match, FC_FILE, 0, &filename) && filename) { - FcChar8 *filename; - if (FcResultMatch == FcPatternGetString(fs->fonts[i], - FC_FILE, 0, - &filename) - && filename) + result.mPath = (const char*)filename; + + // .ttc/.otc collections carry several faces; get the right one. + int index = 0; + if (FcResultMatch == FcPatternGetInteger(match, FC_INDEX, 0, &index)) { - rtns.push_back(std::string((const char*)filename)); - if (rtns.size() >= max_font_count_cutoff) - break; // hit limit + result.mFaceIndex = index; } } - FcFontSetDestroy (fs); + FcPatternDestroy(match); } - LL_DEBUGS() << "Using font list: " << LL_ENDL; - for (std::vector<std::string>::iterator it = rtns.begin(); - it != rtns.end(); - ++it) - { - LL_DEBUGS() << " file: " << *it << LL_ENDL; - } - LL_INFOS() << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << LL_ENDL; - - rtns.push_back(final_fallback); - return rtns; + FcPatternDestroy(pat); + FcCharSetDestroy(charset); +#endif + return result; } void LLWindowSDL::setLanguageTextInput(const LLCoordGL& position) @@ -2261,5 +1963,78 @@ void LLWindowSDL::setLanguageTextInput(const LLCoordGL& position) r.w = 500; r.h = 16; - SDL_SetTextInputRect(&r); + 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 d9b6be5fdc..7156ad66b7 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -24,37 +24,35 @@ * $/LicenseInfo$ */ -#ifndef LL_LLWINDOWSDL2_H -#define LL_LLWINDOWSDL2_H +#ifndef LL_LLWINDOWSDL_H +#define LL_LLWINDOWSDL_H // Simple Directmedia Layer (http://libsdl.org/) implementation of LLWindow class #include "llwindow.h" #include "lltimer.h" +#include "llmutex.h" -#if !defined(__i386__) && !defined(__x86_64__) && !_M_X64 -#define SDL_DISABLE_IMMINTRIN_H +#include "SDL3/SDL.h" +#include "SDL3/SDL_endian.h" + +#ifdef LL_WAYLAND +#include <wayland-client-protocol.h> #endif -#include "SDL2/SDL.h" -#include "SDL2/SDL_video.h" -#include "SDL2/SDL_endian.h" #if LL_X11 -// get X11-specific headers for use in low-level stuff like copy-and-paste support -#include "SDL2/SDL_syswm.h" +#include <X11/Xlib.h> +#include <X11/Xutil.h> #endif -// AssertMacros.h does bad things. -#include "fix_macros.h" -#undef verify -#undef require - +class LLPreeditor; -class LLWindowSDL : public LLWindow { +class LLWindowSDL final : public LLWindow +{ public: void show() override; - void hide() override; + void restore() override; void close() override; @@ -65,23 +63,16 @@ public: bool getMaximized() override; bool maximize() override; - void minimize() override; - void restore() override; - - bool getFullscreen(); - 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, @@ -90,88 +81,67 @@ public: bool setCursorPosition(LLCoordWindow position) override; bool getCursorPosition(LLCoordWindow *position) override; - bool isWrapMouse() const override { return true; } - void showCursor() override; - void hideCursor() override; + bool isCursorHidden() override; void showCursorFromMouseMove() override; - void hideCursorUntilMouseMove() override; - bool isCursorHidden() override; - void updateCursor() override; void captureMouse() override; - void releaseMouse() override; void setMouseClipping(bool b) override; - void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true) 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 - U32 getFSAASamples() override; + bool restoreGamma() override; // Restore original gamma table (before updating gamma) + U32 getFSAASamples() override; void setFSAASamples(const U32 samples) override; - bool restoreGamma() override; // Restore original gamma table (before updating gamma) - ESwapMethod getSwapMethod() override { return mSwapMethod; } - void processMiscNativeEvents() override; void gatherInput() override; - void swapBuffers() override; + SDL_AppResult handleEvent(const SDL_Event& event); + static SDL_AppResult handleEvents(const SDL_Event& event); - void restoreGLContext() {}; + void swapBuffers() override; void delayInputProcessing() override {}; // handy coordinate space conversion routines 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; F32 getNativeAspectRatio() override; - F32 getPixelAspectRatio() override; - void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } - F32 getSystemUISize() override; - void beforeDialog() override; - void afterDialog() override; bool dialogColorPicker(F32 *r, F32 *g, F32 *b) override; @@ -187,38 +157,24 @@ public: void setTitle(const std::string title) override; static std::vector<std::string> getDynamicFallbackFontList(); + static LLFontFallbackMatch findFallbackFontForChar(llwchar wch); - // Not great that these are public, but they have to be accessible - // by non-class code and it's better than making them global. -#if LL_X11 - Window mSDL_XWindowID; - Display *mSDL_Display; -#endif - - void (*Lock_Display)(void); - - void (*Unlock_Display)(void); - -#if LL_X11 - - static Window get_SDL_XWindowID(void); + void *createSharedContext() override; + void makeContextCurrent(void *context) override; + void destroySharedContext(void *context) override; + void toggleVSync(bool enable_vsync) override; - static Display *get_SDL_Display(void); + F32 getSystemUISize() override; -#endif // LL_X11 + static std::vector<std::string> getDisplaysResolutionList(); #if LL_DARWIN + static U64 getVramSize(); + static void setUseMultGL(bool use_mult_gl); + static bool sUseMultGL; #endif - void *createSharedContext() override; - - void makeContextCurrent(void *context) override; - - void destroySharedContext(void *context) override; - - void toggleVSync(bool enable_vsync) override; - protected: LLWindowSDL(LLWindowCallbacks *callbacks, const std::string &title, const std::string& name, int x, int y, int width, int height, U32 flags, @@ -232,19 +188,8 @@ protected: LLSD getNativeKeyData() override; void initCursors(); - void quitCursors(); - void moveWindow(const LLCoordScreen &position, const LLCoordScreen &size); - - // Changes display resolution. Returns true if successful - bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); - - // Go back to last fullscreen display resolution. - bool setFullscreenResolution(); - - bool shouldPostQuit() { return mPostQuit; } - protected: // // Platform specific methods @@ -252,50 +197,65 @@ 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 enable_vsync); - void destroyContext(); void setupFailure(const std::string &text, const std::string &caption, U32 type); - U32 SDLCheckGrabbyKeys(U32 keysym, bool gain); - bool SDLReallyCaptureInput(bool capture); + U32 SDLCheckGrabbyKeys(U32 keysym, bool gain); // // Platform specific variables // - U32 mGrabbyKeyFlags; - int mReallyCapturedCount; - - SDL_Window *mWindow; + U32 mGrabbyKeyFlags = 0; + S32 mReallyCapturedCount = 0; + SDL_Window *mWindow = nullptr; SDL_GLContext mContext; SDL_Cursor *mSDLCursors[UI_CURSOR_COUNT]; std::string mWindowTitle; - double mOriginalAspectRatio; - bool mNeedsResize; // Constructor figured out the window is too big, it needs a resize. - LLCoordScreen mNeedsResizeSize; - F32 mOverrideAspectRatio; - F32 mGamma; - U32 mFSAASamples; - - int mSDLFlags; - - int mHaveInputFocus; /* 0=no, 1=yes, else unknown */ - int mIsMinimized; /* 0=no, 1=yes, else unknown */ + F32 mNativeAspectRatio = 0.0f; + F32 mOverrideAspectRatio = 0.0f; + F32 mGamma = 0.0f; + U32 mFSAASamples = 0; friend class LLWindowManager; private: - bool mFlashing; + bool mFlashing = false; LLTimer mFlashTimer; - U32 mKeyVirtualKey; - U32 mKeyModifiers; - std::string mInputType; + U32 mKeyVirtualKey = 0; + U32 mKeyModifiers = SDL_KMOD_NONE; + LLMutex mOSRMutex; + std::unordered_map<SDL_GLContext, SDL_Window*> mOSRContexts; + std::list<SDL_Window*> mDeadOSRWindows; -private: 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 @@ -304,9 +264,9 @@ public: LLSplashScreenSDL(); virtual ~LLSplashScreenSDL(); - void showImpl(); - void updateImpl(const std::string& mesg); - 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 5793254ded..7f371ff0cf 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -177,6 +177,19 @@ void show_window_creation_error(const std::string& title) LL_WARNS("Window") << title << LL_ENDL; } +static bool is_thread_from_current_process(DWORD thread_id) +{ + HANDLE thread_handle = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, thread_id); + if (!thread_handle) + { + return false; + } + + const DWORD process_id = GetProcessIdOfThread(thread_handle); + CloseHandle(thread_handle); + return process_id == GetCurrentProcessId(); +} + HGLRC SafeCreateContext(HDC &hdc) { __try @@ -214,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; @@ -518,6 +532,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, : LLWindow(callbacks, fullscreen, flags), mAbsoluteCursorPosition(false), + mReceivedSCClose(false), mMaxGLVersion(max_gl_version), mMaxCores(max_cores) { @@ -525,7 +540,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 @@ -1432,7 +1447,7 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo catch (...) { LOG_UNHANDLED_EXCEPTION("ChoosePixelFormat"); - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); close(); return false; } @@ -1443,7 +1458,7 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtDescErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtDescErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); close(); return false; } @@ -1481,7 +1496,7 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo if (!SetPixelFormat(mhDC, pixel_format, &pfd)) { - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtSetErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtSetErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); close(); return false; } @@ -1489,14 +1504,14 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo if (!(mhRC = SafeCreateContext(mhDC))) { - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); close(); return false; } if (!wglMakeCurrent(mhDC, mhRC)) { - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextActErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextActErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); close(); return false; } @@ -1702,14 +1717,14 @@ const S32 max_format = (S32)num_formats - 1; if (!mhDC) { - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBDevContextErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBDevContextErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); close(); return false; } if (!SetPixelFormat(mhDC, pixel_format, &pfd)) { - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtSetErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtSetErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); close(); return false; } @@ -1741,7 +1756,7 @@ const S32 max_format = (S32)num_formats - 1; { LL_WARNS("Window") << "No wgl_ARB_pixel_format extension!" << LL_ENDL; // cannot proceed without wgl_ARB_pixel_format extension, shutdown same as any other gGLManager.initGL() failure - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); close(); return false; } @@ -1750,7 +1765,7 @@ const S32 max_format = (S32)num_formats - 1; if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtDescErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBPixelFmtDescErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); close(); return false; } @@ -1772,14 +1787,16 @@ const S32 max_format = (S32)num_formats - 1; if (!wglMakeCurrent(mhDC, mhRC)) { - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextActErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextActErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); close(); return false; } + gGLManager.initWGL(); // Reinit WGL functions once we have our full context + if (!gGLManager.initGL()) { - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); close(); return false; } @@ -1987,7 +2004,7 @@ void* LLWindowWin32::createSharedContext() if (!rc && !(rc = wglCreateContext(mhDC))) { close(); - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextErr"), 8/*LAST_EXEC_GRAPHICS_INIT*/); + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBGLContextErr"), LLError::LLUserWarningMsg::ERROR_INIT_FAILED); } return rc; @@ -2472,6 +2489,15 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ update_width, update_height)); break; } + case WM_ERASEBKGND: + { + RECT client_rect; + if (GetClientRect(h_wnd, &client_rect)) + { + FillRect((HDC)w_param, &client_rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); + } + return 1; + } case WM_PARENTNOTIFY: { break; @@ -2506,23 +2532,27 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; } - case WM_POWERBROADCAST: - { - // Might need to register for power broadcast interface - // Todo: log monitor suspending and resuming. - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_POWERBROADCAST"); - LL_INFOS("Window") << "Received WM_POWERBROADCAST with wParam: 0x" << std::hex << (uintptr_t)w_param << " lParam: 0x" << (uintptr_t)l_param << std::dec << LL_ENDL; - break; - } - case WM_ACTIVATEAPP: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATEAPP"); + // Resolve ownership before deferring the work because thread IDs can + // be reused after a thread exits. + const bool activating_same_process_thread = + !w_param && is_thread_from_current_process(static_cast<DWORD>(l_param)); window_imp->post([=]() { // This message should be sent whenever the app gains or loses focus. BOOL activating = (BOOL)w_param; + // Native dialogs run on a worker thread. Moving focus between + // the viewer and one of those dialogs must not be treated as + // switching to another application: in fullscreen that would + // minimize the viewer and hide its owned dialog. + if (!activating && activating_same_process_thread) + { + activating = TRUE; + } + if (window_imp->mFullscreen) { // When we run fullscreen, restoring or minimizing the app needs @@ -2572,8 +2602,15 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_SYSCOMMAND: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSCOMMAND"); - switch (w_param) + switch (w_param & 0xFFF0) { + case SC_CLOSE: + // User clicked close from system menu/taskbar or 'end process' from task manager + // Do nothing, will cause WM_CLOSE. + // If we don't get this message before WM_CLOSE, we are likely getting + // a kill from some external program. Win11 task manager Does cause SC_CLOSE. + window_imp->mReceivedSCClose = true; + break; case SC_KEYMENU: // Disallow the ALT key from triggering the default system menu. return 0; @@ -2589,9 +2626,30 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CLOSE"); window_imp->mWindowThread->pingWindowTimeout("WM_CLOSE"); - // todo: WM_CLOSE can be caused by user and by task manager, - // distinguish these cases. - // For now assume it is always user. + + window_imp->mCallbacks->handlePreCloseRequest(); // mark app as potentially closing + if (!window_imp->mReceivedSCClose) + { + // Some external program is trying to close the app. + // Assume that it's going to destroy process if it fails + // and try to fast-quit without confirmation or cleanup. + window_imp->post([=]() + { + // Check if app needs cleanup or can be closed immediately. + if (window_imp->mCallbacks->handleSessionExit(window_imp)) + { + // Get the app to initiate cleanup. + window_imp->mCallbacks->handleQuit(window_imp); + } + }); + return 0; + } + window_imp->mReceivedSCClose = false; + + // There is no way to tell the difference between a user issued + // WM_CLOSE or task manager's WM_CLOSE. + // Assume it is a user and ask for confirmation, but create a marker file. + // If App keeps doing something after a second, or gets 'destroy' message clear the marker. window_imp->post([=]() { // Will the app allow the window to close? @@ -2613,6 +2671,16 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } return 0; } + case WM_NCDESTROY: + LL_INFOS("Window") << "Received WM_NCDESTROY" << LL_ENDL; + break; + case WM_WTSSESSION_CHANGE: + { + // Detects Remote Desktop disconnects, fast user switching, session logoff + // w_param: WTS_CONSOLE_CONNECT, WTS_CONSOLE_DISCONNECT, WTS_SESSION_LOGOFF, etc. + LL_INFOS("Window") << "Received WM_WTSSESSION_CHANGE with wParam: " << (U32)w_param << LL_ENDL; + break; + } case WM_QUERYENDSESSION: { // Generally means that OS is going to shut down or user is going to log off. @@ -2635,8 +2703,10 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ || (end_session_flags & ENDSESSION_CRITICAL) // will shutdown regardless of app state || (end_session_flags & ENDSESSION_LOGOFF)) // logoff, can delay shutdown { + window_imp->mCallbacks->handlePreCloseRequest(); // mark app as closing window_imp->post([=]() { + LL_INFOS("Window") << "Shutting down due to session terminating" << LL_ENDL; // Check if app needs cleanup or can be closed immediately. if (window_imp->mCallbacks->handleSessionExit(window_imp)) { @@ -2655,6 +2725,193 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // if session is ending OS is going to take care of it. return 0; } + case WM_POWERBROADCAST: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_POWERBROADCAST"); + switch (w_param) + { + case PBT_APMSUSPEND: + LL_INFOS("Window") << "System is suspending (sleep/hibernate)" << LL_ENDL; + // System is about to enter sleep or hibernation + // Viewer can't function in hibernation, try to shut down. + // The system allows approximately two seconds for an + // application to handle this notification. + + // Mark app as potentially closing, to minimize issues if OS does not recover. + window_imp->mCallbacks->handlePreCloseRequest(); + window_imp->post([=]() + { + window_imp->mCallbacks->handleSuspendRequest(); + }); + // Window thread normally doesn't block main thread, but OS can suspend + // immediately if we don't wait. + // Keep OS from suspending to give a chance to send stats. + ms_sleep(1000); + return TRUE; + + case PBT_APMRESUMESUSPEND: + LL_INFOS("Window") << "System is resuming from suspend" << LL_ENDL; + window_imp->mCallbacks->handleCloseRequestCanceled(); + return TRUE; + + case PBT_APMPOWERSTATUSCHANGE: + LL_INFOS("Window") << "Power status has changed" << LL_ENDL; + // Power status change (AC/battery) + // Viewer requires high performance, not much we can do. + // about it, but log for diagnostic purposes (example: + // OS trying to throw viewer at an iGPU after this message) + return TRUE; + + default: + LL_INFOS("Window") << "Received WM_POWERBROADCAST with wParam: 0x" << std::hex << (uintptr_t)w_param << " lParam: 0x" << (uintptr_t)l_param << std::dec << LL_ENDL; + break; + } + break; + } + case WM_POST_UNINSTALL_: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_POST_UNINSTALL_"); + // Other instance, likely velopack, requested we quit. + // Don't trust PID alone (can be spoofed), verify the + // path for security purposes before processing. + // Verifying path isn't a strong varranty, if this turns + // up to be a risk, we will want something more secure. + // See sendShutdownToOtherInstances for the sender. + + // LPARAM contains message type. + DWORD message_type = static_cast<DWORD>(l_param); + if (message_type == WM_POST_UNINSTALL_MSG_SHUTDOWN || message_type == WM_POST_UNINSTALL_MSG_UPDATE) + { + DWORD sender_process_id = static_cast<DWORD>(w_param); + + // Make sure something didn't just send us our own process + DWORD our_process_id = GetCurrentProcessId(); + if (our_process_id == sender_process_id) + { + LL_WARNS("Window") << "Received WM_POST_UNINSTALL_ from our own process, ignoring" << LL_ENDL; + break; + } + + if (sender_process_id == 0) + { + LL_WARNS("Window") << "Received WM_POST_UNINSTALL_ but couldn't get sender process ID" << LL_ENDL; + break; + } + + // Open the existing sender process to verify its executable path + HANDLE hSenderProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, sender_process_id); + if (!hSenderProcess) + { + LL_WARNS("Window") << "Received WM_POST_UNINSTALL_ but couldn't open sender process" << LL_ENDL; + break; + } + + // Get the actual executable path of the sender + wchar_t sender_exe_path[MAX_PATH]; + DWORD size = MAX_PATH; + bool got_sender_path = QueryFullProcessImageNameW(hSenderProcess, 0, sender_exe_path, &size) != 0; + CloseHandle(hSenderProcess); + + if (!got_sender_path) + { + LL_WARNS("Window") << "Received WM_POST_UNINSTALL_ but couldn't query sender executable path" << LL_ENDL; + break; + } + + // Extract directory from sender's executable path + wchar_t sender_dir[MAX_PATH]; + wchar_t* file_part = nullptr; + DWORD result = GetFullPathNameW(sender_exe_path, MAX_PATH, sender_dir, &file_part); + + if (result == 0 || result >= MAX_PATH) + { + LL_WARNS("Window") << "Failed to normalize sender executable path" << LL_ENDL; + break; + } + + // Remove the filename to get just directory + if (file_part) + { + *file_part = L'\0'; + } + + // Remove trailing backslash + size_t sender_dir_len = wcslen(sender_dir); + if (sender_dir_len > 0 && sender_dir[sender_dir_len - 1] == L'\\') + { + sender_dir[sender_dir_len - 1] = L'\0'; + sender_dir_len--; + } + + // Remove "\current" suffix from sender's path if present + const std::wstring current_suffix = L"\\current"; + std::wstring sender_normalized_str(sender_dir); + if (sender_normalized_str.length() >= current_suffix.length() && + _wcsicmp(sender_normalized_str.c_str() + sender_normalized_str.length() - current_suffix.length(), + current_suffix.c_str()) == 0) + { + sender_normalized_str.resize(sender_normalized_str.length() - current_suffix.length()); + } + + // Get our executable directory for comparison + std::wstring our_wide = ll_convert<std::wstring>(gDirUtilp->getExecutableDir()); + + // Normalize our path + wchar_t our_normalized[MAX_PATH]; + file_part = nullptr; + + DWORD result2 = GetFullPathNameW(our_wide.c_str(), MAX_PATH, our_normalized, &file_part); + + if (result2 == 0 || result2 >= MAX_PATH) + { + LL_WARNS("Window") << "Failed to normalize our executable path" << LL_ENDL; + break; + } + + // Remove trailing backslash + size_t our_len = wcslen(our_normalized); + if (our_len > 0 && our_normalized[our_len - 1] == L'\\') + { + our_normalized[our_len - 1] = L'\0'; + our_len--; + } + + // Remove "\current" suffix from our path if present + std::wstring our_normalized_str(our_normalized); + if (our_normalized_str.length() >= current_suffix.length() && + _wcsicmp(our_normalized_str.c_str() + our_normalized_str.length() - current_suffix.length(), + current_suffix.c_str()) == 0) + { + our_normalized_str.resize(our_normalized_str.length() - current_suffix.length()); + } + + // Compare the normalized base installation paths (case-insensitive) + if (_wcsicmp(sender_normalized_str.c_str(), our_normalized_str.c_str()) == 0) + { + window_imp->post([=]() + { + LL_INFOS("Window") << "Received valid shutdown request from verified same installation directory" << LL_ENDL; + // Check if app needs cleanup or can be closed immediately. + if (window_imp->mCallbacks->handleCloseRequest(window_imp, false)) + { + // Get the app to initiate cleanup. + window_imp->mCallbacks->handleQuit(window_imp); + } + }); + } + else + { + LL_WARNS("Window") << "Rejected shutdown request - sender not from our installation directory. " + << "Sender: " << ll_convert_wide_to_string(sender_normalized_str) + << " Our: " << ll_convert_wide_to_string(our_normalized_str) << LL_ENDL; + } + } + else + { + LL_WARNS("Window") << "Received invalid WM_POST_UNINSTALL_ message" << LL_ENDL; + } + break; + } case WM_COMMAND: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COMMAND"); @@ -3183,9 +3440,19 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_DISPLAYCHANGE: { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DISPLAYCHANGE"); window_imp->mWindowThread->pingWindowTimeout("WM_DISPLAYCHANGE"); - WINDOW_IMP_POST(window_imp->mCallbacks->handleDisplayChanged()); - break; + window_imp->post([=]() { + window_imp->mCallbacks->handleDisplayChanged(); + // Note: WM_DISPLAYCHANGE was passing to WM_SETFOCUS + // which might have been unintended and was messing with zones. + // handleFocus was copied over and return 0 added, but + // handleFocus might be not needed here. + // handleFocus resets mouse, closes popups and keys, which + // we probablt should do on 'display change'. + window_imp->mCallbacks->handleFocus(window_imp); + }); + return 0; } case WM_SETFOCUS: @@ -5053,6 +5320,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(); @@ -5064,6 +5343,12 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList() // Fonts previously in getFontListSans() have moved to fonts.xml. return std::vector<std::string>(); } + +LLFontFallbackMatch LLWindowWin32::findFallbackFontForChar(llwchar wch) +{ + // Not implemented on Windows; would use DirectWrite (IDWriteFontFallback::MapCharacters). + return LLFontFallbackMatch(); +} #endif // LL_WINDOWS inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index aab2635a34..0b104c6da8 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -40,6 +40,12 @@ // Hack for async host by name #define LL_WM_HOST_RESOLVED (WM_APP + 1) +// For requesting shutdown on uninstall, +// make sure it does not conflict with messages like WM_DUMMY_ +inline constexpr UINT WM_POST_UNINSTALL_ = WM_USER + 0x0019; +inline constexpr DWORD WM_POST_UNINSTALL_MSG_SHUTDOWN = 1; +inline constexpr DWORD WM_POST_UNINSTALL_MSG_UPDATE = 2; + typedef void (*LLW32MsgCallback)(const MSG &msg); class LLWindowWin32 : public LLWindow @@ -124,8 +130,10 @@ 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 LLFontFallbackMatch findFallbackFontForChar(llwchar wch); static void setDPIAwareness(); void* getDirectInput8() override; @@ -232,6 +240,7 @@ protected: LPWSTR mIconResource; LPWSTR mIconSmallResource; bool mInputProcessingPaused; + bool mReceivedSCClose; // received SC_CLOSE and expecting WM_CLOSE // The following variables are for Language Text Input control. // They are all static, since one context is shared by all LLWindowWin32 @@ -258,6 +267,8 @@ protected: bool mMouseVanish; + static HMODULE sGLDLLHandle; + // Cached values of GetWindowRect and GetClientRect to be used by app thread void updateWindowRect(); RECT mRect; |
