summaryrefslogtreecommitdiff
path: root/indra/llwindow
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llwindow')
-rw-r--r--indra/llwindow/CMakeLists.txt227
-rw-r--r--indra/llwindow/llappdelegate-objc.h11
-rw-r--r--indra/llwindow/lldxhardware.cpp4
-rw-r--r--indra/llwindow/llkeyboard.cpp8
-rw-r--r--indra/llwindow/llkeyboard.h21
-rw-r--r--indra/llwindow/llkeyboardheadless.cpp17
-rw-r--r--indra/llwindow/llkeyboardheadless.h21
-rw-r--r--indra/llwindow/llkeyboardmacosx.cpp47
-rw-r--r--indra/llwindow/llkeyboardmacosx.h16
-rw-r--r--indra/llwindow/llkeyboardsdl.cpp692
-rw-r--r--indra/llwindow/llkeyboardsdl.h38
-rw-r--r--indra/llwindow/llkeyboardwin32.cpp4
-rw-r--r--indra/llwindow/llkeyboardwin32.h17
-rw-r--r--indra/llwindow/llmousehandler.cpp2
-rw-r--r--indra/llwindow/llopenglview-objc.h22
-rw-r--r--indra/llwindow/llopenglview-objc.mm580
-rw-r--r--indra/llwindow/llsdl.cpp149
-rw-r--r--indra/llwindow/llsdl.h34
-rw-r--r--indra/llwindow/llwindow.cpp77
-rw-r--r--indra/llwindow/llwindow.h25
-rw-r--r--indra/llwindow/llwindowcallbacks.cpp26
-rw-r--r--indra/llwindow/llwindowcallbacks.h10
-rw-r--r--indra/llwindow/llwindowheadless.h3
-rw-r--r--indra/llwindow/llwindowmacosx-objc.h11
-rw-r--r--indra/llwindow/llwindowmacosx-objc.mm283
-rw-r--r--indra/llwindow/llwindowmacosx.cpp74
-rw-r--r--indra/llwindow/llwindowmacosx.h19
-rw-r--r--indra/llwindow/llwindowmacosx_iokit.h35
-rw-r--r--indra/llwindow/llwindowmesaheadless.h121
-rw-r--r--indra/llwindow/llwindowsdl.cpp1684
-rw-r--r--indra/llwindow/llwindowsdl.h186
-rw-r--r--indra/llwindow/llwindowwin32.cpp1222
-rw-r--r--indra/llwindow/llwindowwin32.h178
33 files changed, 3473 insertions, 2391 deletions
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt
index 6debd54665..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,75 +102,43 @@ 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(
llkeyboardmacosx.cpp
llwindowmacosx.cpp
PROPERTIES
- COMPILE_FLAGS "-Wno-deprecated-declarations -fpascal-strings"
+ 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,22 +204,61 @@ 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)
- find_library(CARBON_LIBRARY Carbon)
target_link_libraries(llwindow ${CARBON_LIBRARY})
endif (DARWIN)
diff --git a/indra/llwindow/llappdelegate-objc.h b/indra/llwindow/llappdelegate-objc.h
index ef36f7d4a8..5b6e11e4e4 100644
--- a/indra/llwindow/llappdelegate-objc.h
+++ b/indra/llwindow/llappdelegate-objc.h
@@ -36,16 +36,17 @@
std::string secondLogPath;
}
-@property (assign) IBOutlet LLNSWindow *window;
-@property (assign) IBOutlet NSWindow *inputWindow;
-@property (assign) IBOutlet LLNonInlineTextView *inputView;
+@property (assign) IBOutlet LLNSWindow * _Nullable window;
+@property (assign) IBOutlet NSWindow * _Nullable inputWindow;
+@property (assign) IBOutlet LLNonInlineTextView * _Nullable inputView;
-@property (retain) NSString *currentInputLanguage;
+@property (retain) NSString * _Nullable currentInputLanguage;
- (void) oneFrame;
-- (void) showInputWindow:(bool)show withEvent:(NSEvent*)textEvent;
+- (void) showInputWindow:(bool)show withEvent:(nullable NSEvent *)textEvent;
- (void) languageUpdated;
- (bool) romanScript;
+- (void) setBugsplatValue:(nullable NSString *)value forAttribute:(nullable NSString *)attribute;
@end
@interface LLApplication : NSApplication
diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp
index 387982dfc2..ff85b2cb14 100644
--- a/indra/llwindow/lldxhardware.cpp
+++ b/indra/llwindow/lldxhardware.cpp
@@ -312,7 +312,7 @@ std::string get_string(IDxDiagContainer *containerp, const WCHAR *wszPropName)
WCHAR wszPropValue[256];
get_wstring(containerp, wszPropName, wszPropValue, 256);
- return utf16str_to_utf8str(wszPropValue);
+ return ll_convert<std::string>(std::wstring(wszPropValue));
}
LLDXHardware::LLDXHardware()
@@ -440,7 +440,7 @@ LLSD LLDXHardware::getDisplayInfo()
// print the value
// windows doesn't guarantee to be null terminated
release_version[RV_SIZE - 1] = NULL;
- ret["DriverVersion"] = utf16str_to_utf8str(release_version);
+ ret["DriverVersion"] = ll_convert<std::string>(std::wstring(release_version));
}
RegCloseKey(hKey);
diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp
index a16c0a318a..df69b1390c 100644
--- a/indra/llwindow/llkeyboard.cpp
+++ b/indra/llwindow/llkeyboard.cpp
@@ -30,6 +30,8 @@
#include "llwindowcallbacks.h"
+#include "llstl.h"
+
//
// Globals
//
@@ -161,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
@@ -196,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())
@@ -226,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;
@@ -254,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 a527227672..a092787cef 100644
--- a/indra/llwindow/llkeyboard.h
+++ b/indra/llwindow/llkeyboard.h
@@ -27,10 +27,9 @@
#ifndef LL_LLKEYBOARD_H
#define LL_LLKEYBOARD_H
+#include <functional>
#include <map>
-#include <boost/function.hpp>
-#include "llstringtable.h"
#include "lltimer.h"
#include "indra_constants.h"
@@ -41,7 +40,7 @@ enum EKeystate
KEYSTATE_UP
};
-typedef boost::function<bool(EKeystate keystate)> LLKeyFunc;
+typedef std::function<bool(EKeystate keystate)> LLKeyFunc;
typedef std::string (LLKeyStringTranslatorFunc)(std::string_view);
enum EKeyboardInsertMode
@@ -55,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();
@@ -73,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 89ff7c6d3f..7d270a4392 100644
--- a/indra/llwindow/llkeyboardmacosx.cpp
+++ b/indra/llwindow/llkeyboardmacosx.cpp
@@ -32,9 +32,32 @@
#include "llwindowmacosx-objc.h"
+#include <CoreServices/CoreServices.h> // Required for TIS functions
+#include <Carbon/Carbon.h>
+
LLKeyboardMacOSX::LLKeyboardMacOSX()
{
// Virtual keycode mapping table. Yes, this was as annoying to generate as it looks.
+
+ bool isAzerty = false;
+
+ TISInputSourceRef source = TISCopyCurrentKeyboardLayoutInputSource();
+ if (source)
+ {
+ CFStringRef inputSourceID = (CFStringRef)TISGetInputSourceProperty(source, kTISPropertyInputSourceID);
+ if (inputSourceID)
+ {
+ char buf[128];
+ // Convert CFString to a C-string for easy comparison
+ if (CFStringGetCString(inputSourceID, buf, sizeof(buf), kCFStringEncodingUTF8))
+ {
+ // On macOS, AZERTY layouts are identified by "French" in their Input Source ID
+ isAzerty = (strstr(buf, "French") != nullptr);
+ }
+ }
+ CFRelease(source);
+ }
+
mTranslateKeyMap[0x00] = 'A';
mTranslateKeyMap[0x01] = 'S';
mTranslateKeyMap[0x02] = 'D';
@@ -52,6 +75,7 @@ LLKeyboardMacOSX::LLKeyboardMacOSX()
mTranslateKeyMap[0x0f] = 'R';
mTranslateKeyMap[0x10] = 'Y';
mTranslateKeyMap[0x11] = 'T';
+
mTranslateKeyMap[0x12] = '1';
mTranslateKeyMap[0x13] = '2';
mTranslateKeyMap[0x14] = '3';
@@ -132,6 +156,16 @@ LLKeyboardMacOSX::LLKeyboardMacOSX()
mTranslateKeyMap[0x7d] = KEY_DOWN;
mTranslateKeyMap[0x7e] = KEY_UP;
+ // azerty fix
+ if(isAzerty)
+ {
+ LL_WARNS() << "keyboard is AZERTY" << LL_ENDL;
+ mTranslateKeyMap[0x00] = 'Q';
+ mTranslateKeyMap[0x06] = 'W';
+ mTranslateKeyMap[0x0c] = 'A';
+ mTranslateKeyMap[0x0d] = 'Z';
+ }
+
// Build inverse map
std::map<U16, KEY>::iterator iter;
for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++)
@@ -162,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.
@@ -187,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;
@@ -203,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;
@@ -226,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;
@@ -243,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;
@@ -262,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;
@@ -291,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 72b4577276..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
@@ -23,11 +24,12 @@
* $/LicenseInfo$
*/
+#include <set>
#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()
{
@@ -38,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;
@@ -70,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;
@@ -112,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++)
@@ -160,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
@@ -174,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
@@ -200,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;
}
@@ -209,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)
{
@@ -234,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);
@@ -254,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);
@@ -278,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;
}
@@ -308,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++)
@@ -322,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/llopenglview-objc.h b/indra/llwindow/llopenglview-objc.h
index 97f4125484..a2c55a2dd9 100644
--- a/indra/llwindow/llopenglview-objc.h
+++ b/indra/llwindow/llopenglview-objc.h
@@ -42,7 +42,11 @@
unsigned int mMarkedTextLength;
bool mMarkedTextAllowed;
bool mSimulatedRightClick;
- bool mOldResize;
+
+ NSOpenGLPixelFormat *pixelFormat;
+ NSOpenGLContext *glContext;
+
+ bool mHDRDisplay;
}
- (id) initWithSamples:(NSUInteger)samples;
- (id) initWithSamples:(NSUInteger)samples andVsync:(BOOL)vsync;
@@ -50,8 +54,6 @@
- (void)commitCurrentPreedit;
-- (void) setOldResize:(bool)oldresize;
-
// rebuildContext
// Destroys and recreates a context with the view's internal format set via setPixelFormat;
// Use this in event of needing to rebuild a context for whatever reason, without needing to assign a new pixel format.
@@ -68,7 +70,6 @@
- (unsigned long) getVramSize;
- (void) allowMarkedTextInput:(bool)allowed;
-- (void) viewDidEndLiveResize;
@end
@@ -88,9 +89,6 @@
@interface LLNSWindow : NSWindow
-- (NSPoint)convertToScreenFromLocalPoint:(NSPoint)point relativeToView:(NSView *)view;
-- (NSPoint)flipPoint:(NSPoint)aPoint;
-
@end
@interface NSScreen (PointConversion)
@@ -100,16 +98,6 @@
*/
+ (NSScreen *)currentScreenForMouseLocation;
-/*
- Allows you to convert a point from global coordinates to the current screen coordinates.
- */
-- (NSPoint)convertPointToScreenCoordinates:(NSPoint)aPoint;
-
-/*
- Allows to flip the point coordinates, so y is 0 at the top instead of the bottom. x remains the same
- */
-- (NSPoint)flipPoint:(NSPoint)aPoint;
-
@end
#endif
diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm
index 6177eb4873..547c921736 100644
--- a/indra/llwindow/llopenglview-objc.mm
+++ b/indra/llwindow/llopenglview-objc.mm
@@ -28,7 +28,10 @@
#import "llwindowmacosx-objc.h"
#import "llappdelegate-objc.h"
+#import <Carbon/Carbon.h>
+
extern BOOL gHiDPISupport;
+extern BOOL gHDRDisplaySupport;
#pragma mark local functions
@@ -105,38 +108,24 @@ attributedStringInfo getSegments(NSAttributedString *str)
return screen;
}
+@end
-- (NSPoint)convertPointToScreenCoordinates:(NSPoint)aPoint
-{
- float normalizedX = fabs(fabs(self.frame.origin.x) - fabs(aPoint.x));
- float normalizedY = aPoint.y - self.frame.origin.y;
-
- return NSMakePoint(normalizedX, normalizedY);
-}
+@implementation LLOpenGLView
-- (NSPoint)flipPoint:(NSPoint)aPoint
+- (NSOpenGLContext*) glContext
{
- return NSMakePoint(aPoint.x, self.frame.size.height - aPoint.y);
+ return glContext;
}
-@end
-
-@implementation LLOpenGLView
-
-// Force a high quality update after live resizing
-- (void) viewDidEndLiveResize
+- (NSOpenGLPixelFormat*) pixelFormat
{
- if (mOldResize) //Maint-3135
- {
- NSSize size = [self frame].size;
- callResize(size.width, size.height);
- }
+ return pixelFormat;
}
- (unsigned long)getVramSize
{
CGLRendererInfoObj info = 0;
- GLint vram_megabytes = 0;
+ GLint vram_megabytes = 0;
int num_renderers = 0;
CGLError the_err = CGLQueryRendererInfo (CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay), &info, &num_renderers);
if(0 == the_err)
@@ -154,51 +143,97 @@ attributedStringInfo getSegments(NSAttributedString *str)
vram_megabytes = 256;
}
- return (unsigned long)vram_megabytes; // return value is in megabytes.
+ return (unsigned long)vram_megabytes; // return value is in megabytes.
+}
+
+- (void)viewWillMoveToWindow:(nullable NSWindow *)newWindow
+{
+ if(mHDRDisplay)
+ {
+ self.wantsExtendedDynamicRangeOpenGLSurface = YES;
+ NSLog(@"Wants Extended Dynamic Range OpenGL", nil);
+ }
+ /*
+ else
+ {
+ self.wantsExtendedDynamicRangeOpenGLSurface = NO;
+ NSLog(@"Wants Standard Color Range OpenGL", nil);
+ }
+ */
}
- (void)viewDidMoveToWindow
{
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(windowResized:) name:NSWindowDidResizeNotification
- object:[self window]];
+ // viewDidMoveToWindow is called both when the view is attached to a window
+ // and when it is detached (window == nil).
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(performDeferredResolutionUpdate)
+ object:nil];
+
+ if (![self window])
+ {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ return;
+ }
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(windowResized:) name:NSWindowDidResizeNotification
+ object:[self window]];
[[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(windowWillMiniaturize:) name:NSWindowWillMiniaturizeNotification
- object:[self window]];
+ selector:@selector(windowWillMiniaturize:) name:NSWindowWillMiniaturizeNotification
+ object:[self window]];
[[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification
- object:[self window]];
+ selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification
+ object:[self window]];
[[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification
- object:[self window]];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(windowDidChangeScreen:) name:NSWindowDidChangeScreenNotification
- object:[self window]];
+ selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification
+ object:[self window]];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(windowDidChangeScreen:) name:NSWindowDidChangeScreenNotification
+ object:[self window]];
- NSRect wnd_rect = [[self window] frame];
- NSRect dev_rect = [self convertRectToBacking:wnd_rect];
- if (!NSEqualSizes(wnd_rect.size,dev_rect.size))
+ if (windowCallbacksReady())
+ {
+ NSRect wnd_rect = [[self window] frame];
+ NSRect dev_rect = [self convertRectToBacking:wnd_rect];
+ if (!NSEqualSizes(wnd_rect.size,dev_rect.size))
+ {
+ // If window size actually changes, update size immediately
+ callResize(dev_rect.size.width, dev_rect.size.height);
+ }
+ else
+ {
+ // Defer size update to let the window settle on its final display
+ // before checkSettings() reads the live backing size.
+ callRequestResolutionUpdate();
+ }
+ }
+ else
{
- callResize(dev_rect.size.width, dev_rect.size.height);
+ // Defer so that mCallbacks is the real callbacks object,
+ // not the null_callbacks used during LLWindowMacOSX construction.
+ // afterDelay will fire on the next loop iteration.
+ NSLog(@"viewDidMoveToWindow triggered, but callbacks not ready, postponing resolution update", nil);
+ [self performSelector:@selector(performDeferredResolutionUpdate) withObject:nil afterDelay:0];
}
}
-- (void)setOldResize:(bool)oldresize
+- (void)performDeferredResolutionUpdate
{
- mOldResize = oldresize;
+ if ([self window])
+ {
+ callRequestResolutionUpdate();
+ }
}
- (void)windowResized:(NSNotification *)notification;
{
- if (!mOldResize) //Maint-3288
- {
- NSSize dev_sz = gHiDPISupport ? [self convertSizeToBacking:[self frame].size] : [self frame].size;
- callResize(dev_sz.width, dev_sz.height);
- }
+ NSSize dev_sz = [self convertSizeToBacking:[self frame].size];
+ callResize(dev_sz.width, dev_sz.height);
}
- (void)windowWillMiniaturize:(NSNotification *)notification;
@@ -218,131 +253,183 @@ attributedStringInfo getSegments(NSAttributedString *str)
-(void)windowDidChangeScreen:(NSNotification *)notification;
{
- callWindowDidChangeScreen();
+ callWindowDidChangeScreen();
}
- (void)dealloc
{
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
}
- (id) init
{
- return [self initWithFrame:[self bounds] withSamples:2 andVsync:TRUE];
+ return [self initWithFrame:[self bounds] withSamples:0 andVsync:FALSE];
}
- (id) initWithSamples:(NSUInteger)samples
{
- return [self initWithFrame:[self bounds] withSamples:samples andVsync:TRUE];
+ return [self initWithFrame:[self bounds] withSamples:samples andVsync:FALSE];
}
- (id) initWithSamples:(NSUInteger)samples andVsync:(BOOL)vsync
{
- return [self initWithFrame:[self bounds] withSamples:samples andVsync:vsync];
+ return [self initWithFrame:[self bounds] withSamples:samples andVsync:vsync];
}
+#if LL_DARWIN
+// For setView and opengl deprecation
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
- (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOOL)vsync
{
- [self registerForDraggedTypes:[NSArray arrayWithObject:NSURLPboardType]];
- [self initWithFrame:frame];
+ NSRect fixedFrame = NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame));
+ [self initWithFrame:fixedFrame];
+ [self setWantsBestResolutionOpenGLSurface:gHiDPISupport];
+
+ // Initialize with a default "safe" pixel format that will work with versions dating back to OS X 10.6.
+ // Any specialized pixel formats, i.e. a core profile pixel format, should be initialized through rebuildContextWithFormat.
+ // 10.7 and 10.8 don't really care if we're defining a profile or not. If we don't explicitly request a core or legacy profile, it'll always assume a legacy profile (for compatibility reasons).
- // Initialize with a default "safe" pixel format that will work with versions dating back to OS X 10.6.
- // Any specialized pixel formats, i.e. a core profile pixel format, should be initialized through rebuildContextWithFormat.
- // 10.7 and 10.8 don't really care if we're defining a profile or not. If we don't explicitly request a core or legacy profile, it'll always assume a legacy profile (for compatibility reasons).
- NSOpenGLPixelFormatAttribute attrs[] = {
+ NSOpenGLPixelFormatAttribute SDRAttrs[] = {
NSOpenGLPFANoRecovery,
- NSOpenGLPFADoubleBuffer,
- NSOpenGLPFAClosestPolicy,
- NSOpenGLPFAAccelerated,
- NSOpenGLPFASampleBuffers, 0,
- NSOpenGLPFASamples, 0,
- NSOpenGLPFAStencilSize, 8,
- NSOpenGLPFADepthSize, 24,
- NSOpenGLPFAAlphaSize, 8,
- NSOpenGLPFAColorSize, 24,
- NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core,
- 0
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAClosestPolicy,
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFADepthSize, 24,
+ NSOpenGLPFAColorSize, 24,
+ NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core,
+ 0
};
- NSOpenGLPixelFormat *pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs] autorelease];
+ NSOpenGLPixelFormatAttribute HDRAttrs[] = {
+ NSOpenGLPFANoRecovery,
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAClosestPolicy,
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFAColorFloat,
+ NSOpenGLPFADepthSize, 24,
+ NSOpenGLPFAColorSize, 48,
+ NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core,
+ 0
+ };
- if (pixelFormat == nil)
- {
- NSLog(@"Failed to create pixel format!", nil);
- return nil;
- }
+ mHDRDisplay = NO;
- NSOpenGLContext *glContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
+ if(gHDRDisplaySupport)
+ {
+ pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:HDRAttrs] autorelease];
+ if (pixelFormat == nil)
+ {
+ NSLog(@"Failed to create pixel format for HDR Display!", nil);
+ pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:SDRAttrs] autorelease];
+ }
+ else
+ {
+ NSLog(@"pixel format created successfully for HDR Display", nil);
+ mHDRDisplay = YES;
+ }
+ }
+ else
+ {
+ pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:SDRAttrs] autorelease];
+ }
- if (glContext == nil)
- {
- NSLog(@"Failed to create OpenGL context!", nil);
- return nil;
- }
+ if (pixelFormat == nil)
+ {
+ NSLog(@"Failed to create pixel format!", nil);
+ return nil;
+ }
- [self setPixelFormat:pixelFormat];
+ glContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
- //for retina support
- [self setWantsBestResolutionOpenGLSurface:gHiDPISupport];
+ if (glContext == nil)
+ {
+ NSLog(@"Failed to create OpenGL context!", nil);
+ return nil;
+ }
+
+ [self setPixelFormat:pixelFormat];
+
+ if(mHDRDisplay)
+ {
+ CGColorSpaceRef color_space = [self.window.colorSpace CGColorSpace];
+ CGColorSpaceRef color_space_extended = CGColorSpaceCreateExtended(color_space);
+ NSColorSpace* extended_ns_color_space
+ = [[NSColorSpace alloc] initWithCGColorSpace:color_space_extended];
+
+ self.window.colorSpace = extended_ns_color_space;
+ CGColorSpaceRelease(color_space_extended);
+
+ NSLog(@"Extended color space applied for HDR Display", nil);
+ }
- [self setOpenGLContext:glContext];
+ [self setOpenGLContext:glContext];
- [glContext setView:self];
+ [glContext setView:self];
- [glContext makeCurrentContext];
+ [glContext makeCurrentContext];
- if (vsync)
- {
- GLint value = 1;
- [glContext setValues:&value forParameter:NSOpenGLCPSwapInterval];
- } else {
- // supress this error after move to Xcode 7:
- // error: null passed to a callee that requires a non-null argument [-Werror,-Wnonnull]
- // Tried using ObjC 'nonnull' keyword as per SO article but didn't build
- GLint swapInterval=0;
- [glContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
- }
+ if (vsync)
+ {
+ GLint value = 1;
+ [glContext setValues:&value forParameter:NSOpenGLContextParameterSwapInterval];
+ } else {
+ // supress this error after move to Xcode 7:
+ // error: null passed to a callee that requires a non-null argument [-Werror,-Wnonnull]
+ // Tried using ObjC 'nonnull' keyword as per SO article but didn't build
+ GLint swapInterval=0;
+ [glContext setValues:&swapInterval forParameter:NSOpenGLContextParameterSwapInterval];
+ }
- mOldResize = false;
+ GLint opacity = 1;
+ [glContext setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity];
- return self;
+ [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeURL]];
+
+ return self;
}
- (BOOL) rebuildContext
{
- return [self rebuildContextWithFormat:[self pixelFormat]];
+ return [self rebuildContextWithFormat:[self pixelFormat]];
}
- (BOOL) rebuildContextWithFormat:(NSOpenGLPixelFormat *)format
{
- NSOpenGLContext *ctx = [self openGLContext];
+ NSOpenGLContext *ctx = [self openGLContext];
- [ctx clearDrawable];
- [ctx initWithFormat:format shareContext:nil];
+ [ctx clearDrawable];
+ [ctx initWithFormat:format shareContext:nil];
- if (ctx == nil)
- {
- NSLog(@"Failed to create OpenGL context!", nil);
- return false;
- }
+ if (ctx == nil)
+ {
+ NSLog(@"Failed to create OpenGL context!", nil);
+ return false;
+ }
- [self setOpenGLContext:ctx];
- [ctx setView:self];
- [ctx makeCurrentContext];
- return true;
+ [self setOpenGLContext:ctx];
+ [ctx setView:self];
+ [ctx makeCurrentContext];
+ return true;
}
+#if LL_DARWIN
+#pragma clang diagnostic pop
+#endif
+
- (CGLContextObj)getCGLContextObj
{
- NSOpenGLContext *ctx = [self openGLContext];
- return (CGLContextObj)[ctx CGLContextObj];
+ NSOpenGLContext *ctx = [self openGLContext];
+ return (CGLContextObj)[ctx CGLContextObj];
}
- (CGLPixelFormatObj*)getCGLPixelFormatObj
{
- NSOpenGLPixelFormat *fmt = [self pixelFormat];
- return (CGLPixelFormatObj*)[fmt CGLPixelFormatObj];
+ NSOpenGLPixelFormat *fmt = [self pixelFormat];
+ return (CGLPixelFormatObj*)[fmt CGLPixelFormatObj];
}
// Various events can be intercepted by our view, thus not reaching our window.
@@ -350,18 +437,14 @@ attributedStringInfo getSegments(NSAttributedString *str)
- (void) mouseDown:(NSEvent *)theEvent
{
- NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow];
- mMousePos[0] = mPoint.x;
- mMousePos[1] = mPoint.y;
-
// Apparently people still use this?
- if ([theEvent modifierFlags] & NSCommandKeyMask &&
- !([theEvent modifierFlags] & NSControlKeyMask) &&
- !([theEvent modifierFlags] & NSShiftKeyMask) &&
- !([theEvent modifierFlags] & NSAlternateKeyMask) &&
- !([theEvent modifierFlags] & NSAlphaShiftKeyMask) &&
- !([theEvent modifierFlags] & NSFunctionKeyMask) &&
- !([theEvent modifierFlags] & NSHelpKeyMask))
+ if ([theEvent modifierFlags] & NSEventModifierFlagCommand &&
+ !([theEvent modifierFlags] & NSEventModifierFlagControl) &&
+ !([theEvent modifierFlags] & NSEventModifierFlagShift) &&
+ !([theEvent modifierFlags] & NSEventModifierFlagOption) &&
+ !([theEvent modifierFlags] & NSEventModifierFlagCapsLock) &&
+ !([theEvent modifierFlags] & NSEventModifierFlagFunction) &&
+ !([theEvent modifierFlags] & NSEventModifierFlagHelp))
{
callRightMouseDown(mMousePos, [theEvent modifierFlags]);
mSimulatedRightClick = true;
@@ -382,7 +465,7 @@ attributedStringInfo getSegments(NSAttributedString *str)
callRightMouseUp(mMousePos, [theEvent modifierFlags]);
mSimulatedRightClick = false;
} else {
- NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow];
+ NSPoint mPoint = [self convertPointToBacking:[theEvent locationInWindow]];
mMousePos[0] = mPoint.x;
mMousePos[1] = mPoint.y;
callLeftMouseUp(mMousePos, [theEvent modifierFlags]);
@@ -391,35 +474,29 @@ attributedStringInfo getSegments(NSAttributedString *str)
- (void) rightMouseDown:(NSEvent *)theEvent
{
- NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow];
- mMousePos[0] = mPoint.x;
- mMousePos[1] = mPoint.y;
- callRightMouseDown(mMousePos, [theEvent modifierFlags]);
+ callRightMouseDown(mMousePos, [theEvent modifierFlags]);
}
- (void) rightMouseUp:(NSEvent *)theEvent
{
- NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow];
- mMousePos[0] = mPoint.x;
- mMousePos[1] = mPoint.y;
- callRightMouseUp(mMousePos, [theEvent modifierFlags]);
+ callRightMouseUp(mMousePos, [theEvent modifierFlags]);
}
- (void)mouseMoved:(NSEvent *)theEvent
{
- NSPoint dev_delta = gHiDPISupport ? [self convertPointToBacking:NSMakePoint([theEvent deltaX], [theEvent deltaY])] : NSMakePoint([theEvent deltaX], [theEvent deltaY]);
+ NSPoint dev_delta = [self convertPointToBacking:NSMakePoint([theEvent deltaX], [theEvent deltaY])];
- float mouseDeltas[] = {
- float(dev_delta.x),
- float(dev_delta.y)
- };
+ float mouseDeltas[] = {
+ float(dev_delta.x),
+ float(dev_delta.y)
+ };
- callDeltaUpdate(mouseDeltas, 0);
+ callDeltaUpdate(mouseDeltas, 0);
- NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow];
- mMousePos[0] = mPoint.x;
- mMousePos[1] = mPoint.y;
- callMouseMoved(mMousePos, 0);
+ NSPoint mPoint = [self convertPointToBacking:[theEvent locationInWindow]];
+ mMousePos[0] = mPoint.x;
+ mMousePos[1] = mPoint.y;
+ callMouseMoved(mMousePos, 0);
}
// NSWindow doesn't trigger mouseMoved when the mouse is being clicked and dragged.
@@ -427,66 +504,60 @@ attributedStringInfo getSegments(NSAttributedString *str)
- (void) mouseDragged:(NSEvent *)theEvent
{
- // Trust the deltas supplied by NSEvent.
- // The old CoreGraphics APIs we previously relied on are now flagged as obsolete.
- // NSEvent isn't obsolete, and provides us with the correct deltas.
+ // Trust the deltas supplied by NSEvent.
+ // The old CoreGraphics APIs we previously relied on are now flagged as obsolete.
+ // NSEvent isn't obsolete, and provides us with the correct deltas.
- NSPoint dev_delta = gHiDPISupport ? [self convertPointToBacking:NSMakePoint([theEvent deltaX], [theEvent deltaY])] : NSMakePoint([theEvent deltaX], [theEvent deltaY]);
+ NSPoint dev_delta = [self convertPointToBacking:NSMakePoint([theEvent deltaX], [theEvent deltaY])];
- float mouseDeltas[] = {
- float(dev_delta.x),
- float(dev_delta.y)
- };
+ float mouseDeltas[] = {
+ float(dev_delta.x),
+ float(dev_delta.y)
+ };
- callDeltaUpdate(mouseDeltas, 0);
+ callDeltaUpdate(mouseDeltas, 0);
- NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow];
- mMousePos[0] = mPoint.x;
- mMousePos[1] = mPoint.y;
- callMouseDragged(mMousePos, 0);
+ NSPoint mPoint = [self convertPointToBacking:[theEvent locationInWindow]];
+ mMousePos[0] = mPoint.x;
+ mMousePos[1] = mPoint.y;
+ callMouseDragged(mMousePos, 0);
}
- (void) otherMouseDown:(NSEvent *)theEvent
{
- NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow];
- mMousePos[0] = mPoint.x;
- mMousePos[1] = mPoint.y;
callOtherMouseDown(mMousePos, [theEvent modifierFlags], [theEvent buttonNumber]);
}
- (void) otherMouseUp:(NSEvent *)theEvent
{
- NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow];
- mMousePos[0] = mPoint.x;
- mMousePos[1] = mPoint.y;
callOtherMouseUp(mMousePos, [theEvent modifierFlags], [theEvent buttonNumber]);
}
- (void) rightMouseDragged:(NSEvent *)theEvent
{
- [self mouseDragged:theEvent];
+ [self mouseDragged:theEvent];
}
- (void) otherMouseDragged:(NSEvent *)theEvent
{
- [self mouseDragged:theEvent];
+ [self mouseDragged:theEvent];
}
- (void) scrollWheel:(NSEvent *)theEvent
{
- callScrollMoved(-[theEvent deltaX], -[theEvent deltaY]);
+ callScrollMoved(-[theEvent deltaX], -[theEvent deltaY]);
}
- (void) mouseExited:(NSEvent *)theEvent
{
- callMouseExit();
+ callMouseExit();
}
- (void) keyUp:(NSEvent *)theEvent
{
NativeKeyEventData eventData = extractKeyDataFromKeyEvent(theEvent);
eventData.mKeyEvent = NativeKeyEventData::KEYUP;
- callKeyUp(&eventData, [theEvent keyCode], [theEvent modifierFlags]);
+ callKeyUp(&eventData, [theEvent keyCode], [theEvent modifierFlags]);
}
- (void) keyDown:(NSEvent *)theEvent
@@ -500,7 +571,7 @@ attributedStringInfo getSegments(NSAttributedString *str)
// Because flagsChange event handler misses event when other window is activated,
// e.g. OS Window for upload something or Input Window...
// mModifiers instance variable is for insertText: or insertText:replacementRange: (by Pell Smit)
- mModifiers = [theEvent modifierFlags];
+ mModifiers = [theEvent modifierFlags];
NSString *str_no_modifiers = [theEvent charactersIgnoringModifiers];
unichar ch = 0;
if (str_no_modifiers.length)
@@ -511,7 +582,7 @@ attributedStringInfo getSegments(NSAttributedString *str)
if (acceptsText &&
!mMarkedTextAllowed &&
- !(mModifiers & (NSControlKeyMask | NSCommandKeyMask)) && // commands don't invoke InputWindow
+ !(mModifiers & (NSEventModifierFlagControl | NSEventModifierFlagCommand)) && // commands don't invoke InputWindow
![(LLAppDelegate*)[NSApp delegate] romanScript] &&
ch > ' ' &&
ch != NSDeleteCharacter &&
@@ -528,20 +599,20 @@ attributedStringInfo getSegments(NSAttributedString *str)
{
NativeKeyEventData eventData = extractKeyDataFromModifierEvent(theEvent);
- mModifiers = [theEvent modifierFlags];
- callModifier([theEvent modifierFlags]);
+ mModifiers = [theEvent modifierFlags];
+ callModifier([theEvent modifierFlags]);
NSInteger mask = 0;
switch([theEvent keyCode])
{
- case 56:
- mask = NSShiftKeyMask;
+ case kVK_Shift:
+ mask = NSEventModifierFlagShift;
break;
- case 58:
- mask = NSAlternateKeyMask;
+ case kVK_Option:
+ mask = NSEventModifierFlagOption;
break;
- case 59:
- mask = NSControlKeyMask;
+ case kVK_Control:
+ mask = NSEventModifierFlagControl;
break;
default:
return;
@@ -570,69 +641,69 @@ attributedStringInfo getSegments(NSAttributedString *str)
- (BOOL) acceptsFirstResponder
{
- return YES;
+ return YES;
}
- (NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender
{
- NSPasteboard *pboard;
+ NSPasteboard *pboard;
NSDragOperation sourceDragMask;
- sourceDragMask = [sender draggingSourceOperationMask];
+ sourceDragMask = [sender draggingSourceOperationMask];
- pboard = [sender draggingPasteboard];
+ pboard = [sender draggingPasteboard];
- if ([[pboard types] containsObject:NSURLPboardType])
- {
- if (sourceDragMask & NSDragOperationLink) {
- NSURL *fileUrl = [[pboard readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]] options:[NSDictionary dictionary]] objectAtIndex:0];
- mLastDraggedUrl = [[fileUrl absoluteString] UTF8String];
+ if ([[pboard types] containsObject:NSPasteboardTypeURL])
+ {
+ if (sourceDragMask & NSDragOperationLink) {
+ NSURL *fileUrl = [[pboard readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]] options:[NSDictionary dictionary]] objectAtIndex:0];
+ mLastDraggedUrl = [[fileUrl absoluteString] UTF8String];
return NSDragOperationLink;
}
- }
- return NSDragOperationNone;
+ }
+ return NSDragOperationNone;
}
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
{
- callHandleDragUpdated(mLastDraggedUrl);
+ callHandleDragUpdated(mLastDraggedUrl);
- return NSDragOperationLink;
+ return NSDragOperationLink;
}
- (void) draggingExited:(id<NSDraggingInfo>)sender
{
- callHandleDragExited(mLastDraggedUrl);
+ callHandleDragExited(mLastDraggedUrl);
}
- (BOOL)prepareForDragOperation:(id < NSDraggingInfo >)sender
{
- return YES;
+ return YES;
}
- (BOOL) performDragOperation:(id<NSDraggingInfo>)sender
{
- callHandleDragDropped(mLastDraggedUrl);
- return true;
+ callHandleDragDropped(mLastDraggedUrl);
+ return true;
}
- (BOOL)hasMarkedText
{
- return mHasMarkedText;
+ return mHasMarkedText;
}
- (NSRange)markedRange
{
- int range[2];
- getPreeditMarkedRange(&range[0], &range[1]);
- return NSMakeRange(range[0], range[1]);
+ int range[2];
+ getPreeditMarkedRange(&range[0], &range[1]);
+ return NSMakeRange(range[0], range[1]);
}
- (NSRange)selectedRange
{
- int range[2];
- getPreeditSelectionRange(&range[0], &range[1]);
- return NSMakeRange(range[0], range[1]);
+ int range[2];
+ getPreeditSelectionRange(&range[0], &range[1]);
+ return NSMakeRange(range[0], range[1]);
}
- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
@@ -657,7 +728,7 @@ attributedStringInfo getSegments(NSAttributedString *str)
};
int string_length = [aString length];
- unichar text[string_length];
+ unichar *text = new unichar[string_length];
attributedStringInfo segments;
// I used 'respondsToSelector:@selector(string)'
// to judge aString is an attributed string or not.
@@ -685,6 +756,8 @@ attributedStringInfo getSegments(NSAttributedString *str)
// we must clear the marked text when aString is null.
[self unmarkText];
}
+
+ delete [] text;
} else {
if (mHasMarkedText)
{
@@ -693,6 +766,12 @@ attributedStringInfo getSegments(NSAttributedString *str)
}
}
+#if LL_DARWIN
+// For commitEditing deprecation
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
- (void)commitCurrentPreedit
{
if (mHasMarkedText)
@@ -704,23 +783,27 @@ attributedStringInfo getSegments(NSAttributedString *str)
}
}
+#if LL_DARWIN
+#pragma clang diagnostic pop
+#endif
+
- (void)unmarkText
{
- [[self inputContext] discardMarkedText];
- resetPreedit();
- mHasMarkedText = FALSE;
+ [[self inputContext] discardMarkedText];
+ resetPreedit();
+ mHasMarkedText = FALSE;
}
// We don't support attributed strings.
- (NSArray *)validAttributesForMarkedText
{
- return [NSArray array];
+ return [NSArray array];
}
// See above.
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
{
- return nil;
+ return nil;
}
- (void)insertText:(id)insertString
@@ -733,9 +816,9 @@ attributedStringInfo getSegments(NSAttributedString *str)
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
{
- // SL-19801 Special workaround for system emoji picker
- if ([aString length] == 2)
- {
+ // SL-19801 Special workaround for system emoji picker
+ if ([aString length] == 2)
+ {
@try
{
uint32_t b0 = [aString characterAtIndex:0];
@@ -753,7 +836,7 @@ attributedStringInfo getSegments(NSAttributedString *str)
NSLog(@"Encountered an unsupported attributed character. Exception: %@ String: %@", e.name, aString);
return;
}
- }
+ }
@try
{
@@ -783,39 +866,39 @@ attributedStringInfo getSegments(NSAttributedString *str)
- (void) insertNewline:(id)sender
{
- if (!(mModifiers & NSCommandKeyMask) &&
- !(mModifiers & NSShiftKeyMask) &&
- !(mModifiers & NSAlternateKeyMask))
- {
- callUnicodeCallback(13, 0);
- } else {
- callUnicodeCallback(13, mModifiers);
- }
+ if (!(mModifiers & NSEventModifierFlagCommand) &&
+ !(mModifiers & NSEventModifierFlagShift) &&
+ !(mModifiers & NSEventModifierFlagOption))
+ {
+ callUnicodeCallback(13, 0);
+ } else {
+ callUnicodeCallback(13, mModifiers);
+ }
}
- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
{
- return NSNotFound;
+ return NSNotFound;
}
- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
{
- float pos[4] = {0, 0, 0, 0};
- getPreeditLocation(pos, mMarkedTextLength);
- return NSMakeRect(pos[0], pos[1], pos[2], pos[3]);
+ float pos[4] = {0, 0, 0, 0};
+ getPreeditLocation(pos, mMarkedTextLength);
+ return NSMakeRect(pos[0], pos[1], pos[2], pos[3]);
}
- (void)doCommandBySelector:(SEL)aSelector
{
- if (aSelector == @selector(insertNewline:))
- {
- [self insertNewline:self];
- }
+ if (aSelector == @selector(insertNewline:))
+ {
+ [self insertNewline:self];
+ }
}
- (BOOL)drawsVerticallyForCharacterAtIndex:(NSUInteger)charIndex
{
- return NO;
+ return NO;
}
- (void) allowMarkedTextInput:(bool)allowed
@@ -850,7 +933,7 @@ attributedStringInfo getSegments(NSAttributedString *str)
- (void) setGLView:(LLOpenGLView *)view
{
- glview = view;
+ glview = view;
}
- (void)keyDown:(NSEvent *)theEvent
@@ -901,45 +984,24 @@ attributedStringInfo getSegments(NSAttributedString *str)
- (id) init
{
- return self;
-}
-
-- (NSPoint)convertToScreenFromLocalPoint:(NSPoint)point relativeToView:(NSView *)view
-{
- NSScreen *currentScreen = [NSScreen currentScreenForMouseLocation];
- if(currentScreen)
- {
- NSPoint windowPoint = [view convertPoint:point toView:nil];
- NSPoint screenPoint = [[view window] convertBaseToScreen:windowPoint];
- NSPoint flippedScreenPoint = [currentScreen flipPoint:screenPoint];
- flippedScreenPoint.y += [currentScreen frame].origin.y;
-
- return flippedScreenPoint;
- }
-
- return NSZeroPoint;
-}
-
-- (NSPoint)flipPoint:(NSPoint)aPoint
-{
- return NSMakePoint(aPoint.x, self.frame.size.height - aPoint.y);
+ return self;
}
- (BOOL) becomeFirstResponder
{
- callFocus();
- return true;
+ callFocus();
+ return true;
}
- (BOOL) resignFirstResponder
{
- callFocusLost();
- return true;
+ callFocusLost();
+ return true;
}
- (void) close
{
- callQuitHandler();
+ callQuitHandler();
}
@end
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 4f3cc69c75..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_WINDOW
+ result = OSMessageBoxSDL(text, caption, type);
#elif LL_WINDOWS
result = OSMessageBoxWin32(text, caption, type);
-#elif LL_DARWIN && !LL_SDL
+#elif LL_DARWIN
result = OSMessageBoxMacOSX(text, caption, type);
-#elif LL_SDL
- result = OSMessageBoxSDL(text, caption, type);
#else
-#error("OSMessageBox not implemented for this platform!")
+ LL_WARNS() << "OSMessageBox not implemented for this platform!" << LL_ENDL;
+ return OSBTN_OK;
#endif
if (was_visible)
@@ -103,7 +107,6 @@ LLWindow::LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags)
mFullscreen(fullscreen),
mFullscreenWidth(0),
mFullscreenHeight(0),
- mFullscreenBits(0),
mFullscreenRefresh(0),
mSupportedResolutions(NULL),
mNumSupportedResolutions(0),
@@ -183,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())
@@ -259,23 +256,39 @@ bool LLWindow::copyTextToPrimary(const LLWString &src)
// static
std::vector<std::string> LLWindow::getDynamicFallbackFontList()
{
-#if LL_WINDOWS
+#if LL_SDL_WINDOW && !LL_MESA_HEADLESS
+ return LLWindowSDL::getDynamicFallbackFontList();
+#elif LL_WINDOWS
return LLWindowWin32::getDynamicFallbackFontList();
-#elif LL_DARWIN && !LL_SDL
+#elif LL_DARWIN
return LLWindowMacOSX::getDynamicFallbackFontList();
-#elif LL_SDL
- return LLWindowSDL::getDynamicFallbackFontList();
#else
return std::vector<std::string>();
#endif
}
// 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_WINDOWS
+#if LL_SDL_WINDOW && !LL_MESA_HEADLESS
+ return LLWindowSDL::getDisplaysResolutionList();
+#elif LL_WINDOWS
return LLWindowWin32::getDisplaysResolutionList();
-#elif LL_DARWIN && !LL_SDL
+#elif LL_DARWIN
return LLWindowMacOSX::getDisplaysResolutionList();
#else
return std::vector<std::string>();
@@ -342,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 && !LL_SDL
+#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
}
@@ -359,9 +375,11 @@ void LLSplashScreen::show()
{
if (!gSplashScreenp)
{
-#if LL_WINDOWS && !LL_MESA_HEADLESS
+#if LL_SDL_WINDOW && !LL_MESA_HEADLESS
+ gSplashScreenp = new LLSplashScreenSDL;
+#elif LL_WINDOWS && !LL_MESA_HEADLESS
gSplashScreenp = new LLSplashScreenWin32;
-#elif LL_DARWIN && !LL_SDL
+#elif LL_DARWIN
gSplashScreenp = new LLSplashScreenMacOSX;
#endif
if (gSplashScreenp)
@@ -411,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)
{
@@ -419,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);
@@ -462,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 5e06e665f3..3f06bf1a50 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>
@@ -71,7 +78,12 @@ public:
virtual void restore() = 0;
bool getFullscreen() { return mFullscreen; };
virtual bool getPosition(LLCoordScreen *position) = 0;
+
+ // Returns the platform-defined window size in physical (backing) pixels.
+ // On macOS: backing content view size (excludes title bar).
+ // On Windows: outer window frame size (includes title bar and borders).
virtual bool getSize(LLCoordScreen *size) = 0;
+
virtual bool getSize(LLCoordWindow *size) = 0;
virtual bool setPosition(LLCoordScreen position) = 0;
bool setSize(LLCoordScreen size);
@@ -92,9 +104,10 @@ public:
virtual bool setCursorPosition(LLCoordWindow position) = 0;
virtual bool getCursorPosition(LLCoordWindow *position) = 0;
-#if LL_WINDOWS
+#if LL_WINDOWS && !LL_SDL_WINDOW
virtual bool getCursorDelta(LLCoordCommon* delta) = 0;
#endif
+ virtual bool isWrapMouse() const = 0;
virtual void showCursor() = 0;
virtual void hideCursor() = 0;
virtual bool isCursorHidden() = 0;
@@ -147,7 +160,6 @@ public:
virtual void swapBuffers() = 0;
virtual void bringToFront() = 0;
virtual void focusClient() { }; // this may not have meaning or be required on other platforms, therefore, it's not abstract
- virtual void setOldResize(bool oldresize) { };
// handy coordinate space conversion routines
// NB: screen to window and vice verse won't work on width/height coordinate pairs,
// as the conversion must take into account left AND right border widths, etc.
@@ -174,9 +186,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 +195,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(); }
@@ -205,6 +217,8 @@ public:
};
virtual S32 getRefreshRate() { return mRefreshRate; }
+
+ virtual void initWatchdog() {} // windows runs window as a thread and it needs a watchdog
protected:
LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags);
virtual ~LLWindow();
@@ -223,7 +237,6 @@ protected:
bool mFullscreen;
S32 mFullscreenWidth;
S32 mFullscreenHeight;
- S32 mFullscreenBits;
S32 mFullscreenRefresh;
LLWindowResolution* mSupportedResolutions;
S32 mNumSupportedResolutions;
diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp
index 195f68e08b..b16d0ffce8 100644
--- a/indra/llwindow/llwindowcallbacks.cpp
+++ b/indra/llwindow/llwindowcallbacks.cpp
@@ -68,7 +68,25 @@ void LLWindowCallbacks::handleMouseLeave(LLWindow *window)
return;
}
-bool LLWindowCallbacks::handleCloseRequest(LLWindow *window)
+void LLWindowCallbacks::handlePreCloseRequest()
+{
+}
+
+void LLWindowCallbacks::handleCloseRequestCanceled()
+{
+}
+
+void LLWindowCallbacks::handleSuspendRequest()
+{
+}
+
+bool LLWindowCallbacks::handleCloseRequest(LLWindow *window, bool from_user)
+{
+ //allow the window to close
+ return true;
+}
+
+bool LLWindowCallbacks::handleSessionExit(LLWindow* window)
{
//allow the window to close
return true;
@@ -138,6 +156,10 @@ void LLWindowCallbacks::handleResize(LLWindow *window, const S32 width, const S3
{
}
+void LLWindowCallbacks::handleRequestResolutionUpdate(LLWindow* window)
+{
+}
+
void LLWindowCallbacks::handleFocus(LLWindow *window)
{
LL_WARNS("COCOA") << "Called handleFocus proto" << LL_ENDL;
@@ -184,7 +206,7 @@ bool LLWindowCallbacks::handleTimerEvent(LLWindow *window)
return false;
}
-bool LLWindowCallbacks::handleDeviceChange(LLWindow *window)
+bool LLWindowCallbacks::handleDeviceChange(LLWindow *window, const std::string& change_type)
{
return false;
}
diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h
index d812f93524..1fcf2974b5 100644
--- a/indra/llwindow/llwindowcallbacks.h
+++ b/indra/llwindow/llwindowcallbacks.h
@@ -41,8 +41,13 @@ 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);
+ virtual bool handleCloseRequest(LLWindow *window, bool from_user);
+ virtual bool handleSessionExit(LLWindow* window);
// window is about to be destroyed, clean up your business
virtual void handleQuit(LLWindow *window);
virtual bool handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask);
@@ -58,6 +63,7 @@ public:
virtual void handleScrollWheel(LLWindow *window, S32 clicks);
virtual void handleScrollHWheel(LLWindow *window, S32 clicks);
virtual void handleResize(LLWindow *window, S32 width, S32 height);
+ virtual void handleRequestResolutionUpdate(LLWindow* window);
virtual void handleFocus(LLWindow *window);
virtual void handleFocusLost(LLWindow *window);
virtual void handleMenuSelect(LLWindow *window, S32 menu_item);
@@ -67,7 +73,7 @@ public:
virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while
virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data);
virtual bool handleTimerEvent(LLWindow *window);
- virtual bool handleDeviceChange(LLWindow *window);
+ virtual bool handleDeviceChange(LLWindow *window, const std::string& change_type);
virtual bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height);
virtual bool handleDisplayChanged();
virtual bool handleWindowDidChangeScreen(LLWindow *window);
diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h
index 5696b69a59..8b7b0ef55c 100644
--- a/indra/llwindow/llwindowheadless.h
+++ b/indra/llwindow/llwindowheadless.h
@@ -60,9 +60,10 @@ public:
/*virtual*/ void toggleVSync(bool enable_vsync) override { }
/*virtual*/ bool setCursorPosition(LLCoordWindow position) override {return false;}
/*virtual*/ bool getCursorPosition(LLCoordWindow *position) override {return false;}
-#if LL_WINDOWS
+#if LL_WINDOWS && !LL_SDL_WINDOW
/*virtual*/ bool getCursorDelta(LLCoordCommon* delta) override { return false; }
#endif
+ /*virtual*/ bool isWrapMouse() const override { return true; }
/*virtual*/ void showCursor() override {}
/*virtual*/ void hideCursor() override {}
/*virtual*/ void showCursorFromMouseMove() override {}
diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h
index d9d8bfce1f..a9698bc0e1 100644
--- a/indra/llwindow/llwindowmacosx-objc.h
+++ b/indra/llwindow/llwindowmacosx-objc.h
@@ -78,6 +78,8 @@ void initMainLoop();
void cleanupViewer();
void handleUrl(const char* url);
void dispatchUrl(std::string url);
+void startWatchdog(std::string_view state);
+void stopWatchdog();
/* Defined in llwindowmacosx-objc.mm: */
int createNSApp(int argc, const char **argv);
@@ -100,7 +102,6 @@ bool isCGCursorVisible();
void hideNSCursorTillMove(bool hide);
void requestUserAttention();
long showAlert(std::string title, std::string text, int type);
-void setResizeMode(bool oldresize, void* glview);
NSWindowRef createNSWindow(int x, int y, int width, int height);
@@ -111,16 +112,14 @@ void glSwapBuffers(void* context);
CGLContextObj getCGLContextObj(GLViewRef view);
unsigned long getVramSize(GLViewRef view);
float getDeviceUnitSize(GLViewRef view);
-CGPoint getContentViewBoundsPosition(NSWindowRef window);
-CGSize getContentViewBoundsSize(NSWindowRef window);
-CGSize getDeviceContentViewSize(NSWindowRef window, GLViewRef view);
+CGRect getContentViewRect(NSWindowRef window);
+CGRect getBackingViewRect(NSWindowRef window, GLViewRef view);
void getWindowSize(NSWindowRef window, float* size);
void setWindowSize(NSWindowRef window, int width, int height);
void getCursorPos(NSWindowRef window, float* pos);
void makeWindowOrderFront(NSWindowRef window);
void convertScreenToWindow(NSWindowRef window, float *coord);
void convertWindowToScreen(NSWindowRef window, float *coord);
-void convertScreenToView(NSWindowRef window, float *coord);
void convertRectToScreen(NSWindowRef window, float *coord);
void convertRectFromScreen(NSWindowRef window, float *coord);
void setWindowPos(NSWindowRef window, float* pos);
@@ -141,6 +140,7 @@ void callLeftMouseDown(float *pos, unsigned int mask);
void callLeftMouseUp(float *pos, unsigned int mask);
void callDoubleClick(float *pos, unsigned int mask);
void callResize(unsigned int width, unsigned int height);
+void callRequestResolutionUpdate();
void callMouseMoved(float *pos, unsigned int mask);
void callMouseDragged(float *pos, unsigned int mask);
void callScrollMoved(float deltaX, float deltaY);
@@ -158,6 +158,7 @@ void callFocusLost();
void callModifier(unsigned int mask);
void callQuitHandler();
void commitCurrentPreedit(GLViewRef glView);
+bool windowCallbacksReady();
#include <string>
void callHandleDragEntered(std::string url);
diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm
index 2e75d309ea..85208a5ac3 100644
--- a/indra/llwindow/llwindowmacosx-objc.mm
+++ b/indra/llwindow/llwindowmacosx-objc.mm
@@ -41,15 +41,15 @@
int createNSApp(int argc, const char *argv[])
{
- return NSApplicationMain(argc, argv);
+ return NSApplicationMain(argc, argv);
}
void setupCocoa()
{
- static bool inited = false;
-
- if(!inited)
- {
+ static bool inited = false;
+
+ if(!inited)
+ {
@autoreleasepool {
// The following prevents the Cocoa command line parser from trying to open 'unknown' arguements as documents.
// ie. running './secondlife -set Language fr' would cause a pop-up saying can't open document 'fr'
@@ -57,8 +57,8 @@ void setupCocoa()
[[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
}
- inited = true;
- }
+ inited = true;
+ }
}
bool copyToPBoard(const unsigned short *str, unsigned int len)
@@ -66,7 +66,7 @@ bool copyToPBoard(const unsigned short *str, unsigned int len)
@autoreleasepool {
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
[pboard clearContents];
-
+
NSArray *contentsToPaste = [[[NSArray alloc] initWithObjects:[NSString stringWithCharacters:str length:len], nil] autorelease];
return [pboard writeObjects:contentsToPaste];
}
@@ -74,8 +74,8 @@ bool copyToPBoard(const unsigned short *str, unsigned int len)
bool pasteBoardAvailable()
{
- NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
- return [[NSPasteboard generalPasteboard] canReadObjectForClasses:classArray options:[NSDictionary dictionary]];
+ NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
+ return [[NSPasteboard generalPasteboard] canReadObjectForClasses:classArray options:[NSDictionary dictionary]];
}
unsigned short *copyFromPBoard()
@@ -111,100 +111,110 @@ CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY)
hotSpot:NSMakePoint(hotspotX, hotspotY)
] retain];
}
-
- return (CursorRef)cursor;
+
+ return (CursorRef)cursor;
}
void setArrowCursor()
{
- NSCursor *cursor = [NSCursor arrowCursor];
- [NSCursor unhide];
- [cursor set];
+ NSCursor *cursor = [NSCursor arrowCursor];
+ [NSCursor unhide];
+ [cursor set];
}
void setIBeamCursor()
{
- NSCursor *cursor = [NSCursor IBeamCursor];
- [cursor set];
+ NSCursor *cursor = [NSCursor IBeamCursor];
+ [cursor set];
}
void setPointingHandCursor()
{
- NSCursor *cursor = [NSCursor pointingHandCursor];
- [cursor set];
+ NSCursor *cursor = [NSCursor pointingHandCursor];
+ [cursor set];
}
void setCopyCursor()
{
- NSCursor *cursor = [NSCursor dragCopyCursor];
- [cursor set];
+ NSCursor *cursor = [NSCursor dragCopyCursor];
+ [cursor set];
}
void setCrossCursor()
{
- NSCursor *cursor = [NSCursor crosshairCursor];
- [cursor set];
+ NSCursor *cursor = [NSCursor crosshairCursor];
+ [cursor set];
}
void setNotAllowedCursor()
{
- NSCursor *cursor = [NSCursor operationNotAllowedCursor];
- [cursor set];
+ NSCursor *cursor = [NSCursor operationNotAllowedCursor];
+ [cursor set];
}
void hideNSCursor()
{
- [NSCursor hide];
+ [NSCursor hide];
}
void showNSCursor()
{
- [NSCursor unhide];
+ [NSCursor unhide];
}
+#if LL_DARWIN
+// For CGCursorIsVisible no replacement in modern API
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
bool isCGCursorVisible()
{
return CGCursorIsVisible();
}
+#if LL_DARWIN
+#pragma clang diagnostic pop
+#endif
+
void hideNSCursorTillMove(bool hide)
{
- [NSCursor setHiddenUntilMouseMoves:hide];
+ [NSCursor setHiddenUntilMouseMoves:hide];
}
// This is currently unused, since we want all our cursors to persist for the life of the app, but I've included it for completeness.
OSErr releaseImageCursor(CursorRef ref)
{
- if( ref != NULL )
- {
+ if( ref != NULL )
+ {
@autoreleasepool {
NSCursor *cursor = (NSCursor*)ref;
[cursor autorelease];
}
- }
- else
- {
- return paramErr;
- }
-
- return noErr;
+ }
+ else
+ {
+ return paramErr;
+ }
+
+ return noErr;
}
OSErr setImageCursor(CursorRef ref)
{
- if( ref != NULL )
- {
+ if( ref != NULL )
+ {
@autoreleasepool {
NSCursor *cursor = (NSCursor*)ref;
[cursor set];
}
- }
- else
- {
- return paramErr;
- }
-
- return noErr;
+ }
+ else
+ {
+ return paramErr;
+ }
+
+ return noErr;
}
// Now for some unholy juggling between generic pointers and casting them to Obj-C objects!
@@ -212,186 +222,155 @@ OSErr setImageCursor(CursorRef ref)
NSWindowRef createNSWindow(int x, int y, int width, int height)
{
- LLNSWindow *window = [[LLNSWindow alloc]initWithContentRect:NSMakeRect(x, y, width, height)
- styleMask:NSTitledWindowMask | NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTexturedBackgroundWindowMask backing:NSBackingStoreBuffered defer:NO];
- [window makeKeyAndOrderFront:nil];
- [window setAcceptsMouseMovedEvents:TRUE];
+ LLNSWindow *window = [[LLNSWindow alloc]initWithContentRect:NSMakeRect(x, y, width, height)
+ styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskFullSizeContentView
+ backing:NSBackingStoreBuffered defer:YES];
+ [window makeKeyAndOrderFront:nil];
+ [window setAcceptsMouseMovedEvents:TRUE];
[window setRestorable:FALSE]; // Viewer manages state from own settings
- return window;
+ return window;
}
GLViewRef createOpenGLView(NSWindowRef window, unsigned int samples, bool vsync)
{
- LLOpenGLView *glview = [[LLOpenGLView alloc]initWithFrame:[(LLNSWindow*)window frame] withSamples:samples andVsync:vsync];
- [(LLNSWindow*)window setContentView:glview];
- return glview;
-}
-
-void setResizeMode(bool oldresize, void* glview)
-{
- [(LLOpenGLView *)glview setOldResize:oldresize];
+ LLOpenGLView *glview = [[LLOpenGLView alloc]initWithFrame:[(LLNSWindow*)window frame] withSamples:samples andVsync:vsync];
+ [(LLNSWindow*)window setContentView:glview];
+ return glview;
}
void glSwapBuffers(void* context)
{
- [(NSOpenGLContext*)context flushBuffer];
+ [(NSOpenGLContext*)context flushBuffer];
}
CGLContextObj getCGLContextObj(GLViewRef view)
{
- return [(LLOpenGLView *)view getCGLContextObj];
+ return [(LLOpenGLView *)view getCGLContextObj];
}
CGLPixelFormatObj* getCGLPixelFormatObj(NSWindowRef window)
{
- LLOpenGLView *glview = [(LLNSWindow*)window contentView];
- return [glview getCGLPixelFormatObj];
+ LLOpenGLView *glview = [(LLNSWindow*)window contentView];
+ return [glview getCGLPixelFormatObj];
}
unsigned long getVramSize(GLViewRef view)
{
- return [(LLOpenGLView *)view getVramSize];
+ return [(LLOpenGLView *)view getVramSize];
}
float getDeviceUnitSize(GLViewRef view)
{
- return [(LLOpenGLView*)view convertSizeToBacking:NSMakeSize(1, 1)].width;
+ return [(LLOpenGLView*)view convertSizeToBacking:NSMakeSize(1, 1)].width;
}
-CGPoint getContentViewBoundsPosition(NSWindowRef window)
+CGRect getContentViewRect(NSWindowRef window)
{
- return [[(LLNSWindow*)window contentView] bounds].origin;
+ return [[(LLNSWindow*)window contentView] bounds];
}
-CGSize getContentViewBoundsSize(NSWindowRef window)
+CGRect getBackingViewRect(NSWindowRef window, GLViewRef view)
{
- return [[(LLNSWindow*)window contentView] bounds].size;
-}
-
-CGSize getDeviceContentViewSize(NSWindowRef window, GLViewRef view)
-{
- return [(NSOpenGLView*)view convertRectToBacking:[[(LLNSWindow*)window contentView] bounds]].size;
+ return [(NSOpenGLView*)view convertRectToBacking:[[(LLNSWindow*)window contentView] bounds]];
}
void getWindowSize(NSWindowRef window, float* size)
{
- NSRect frame = [(LLNSWindow*)window frame];
- size[0] = frame.origin.x;
- size[1] = frame.origin.y;
- size[2] = frame.size.width;
- size[3] = frame.size.height;
+ NSRect frame = [(LLNSWindow*)window frame];
+ size[0] = frame.origin.x;
+ size[1] = frame.origin.y;
+ size[2] = frame.size.width;
+ size[3] = frame.size.height;
}
void setWindowSize(NSWindowRef window, int width, int height)
{
- NSRect frame = [(LLNSWindow*)window frame];
- frame.size.width = width;
- frame.size.height = height;
- [(LLNSWindow*)window setFrame:frame display:TRUE];
+ NSRect frame = [(LLNSWindow*)window frame];
+ frame.size.width = width;
+ frame.size.height = height;
+ [(LLNSWindow*)window setFrame:frame display:TRUE];
}
void setWindowPos(NSWindowRef window, float* pos)
{
- NSPoint point;
- point.x = pos[0];
- point.y = pos[1];
- [(LLNSWindow*)window setFrameOrigin:point];
+ NSPoint point;
+ point.x = pos[0];
+ point.y = pos[1];
+ [(LLNSWindow*)window setFrameOrigin:point];
}
void getCursorPos(NSWindowRef window, float* pos)
{
- NSPoint mLoc;
- mLoc = [(LLNSWindow*)window mouseLocationOutsideOfEventStream];
- pos[0] = mLoc.x;
- pos[1] = mLoc.y;
+ NSPoint mLoc;
+ mLoc = [(LLNSWindow*)window mouseLocationOutsideOfEventStream];
+ pos[0] = mLoc.x;
+ pos[1] = mLoc.y;
}
void makeWindowOrderFront(NSWindowRef window)
{
- [(LLNSWindow*)window makeKeyAndOrderFront:nil];
+ [(LLNSWindow*)window makeKeyAndOrderFront:nil];
}
void convertScreenToWindow(NSWindowRef window, float *coord)
{
- NSRect point;
- point.origin.x = coord[0];
- point.origin.y = coord[1];
- point = [(LLNSWindow*)window convertRectFromScreen:point];
- coord[0] = point.origin.x;
- coord[1] = point.origin.y;
+ NSRect point = NSMakeRect(coord[0], coord[1], 0,0);
+ point = [(LLNSWindow*)window convertRectFromScreen:point];
+ coord[0] = point.origin.x;
+ coord[1] = point.origin.y;
}
void convertRectToScreen(NSWindowRef window, float *coord)
{
- NSRect point;
- point.origin.x = coord[0];
- point.origin.y = coord[1];
- point.size.width = coord[2];
- point.size.height = coord[3];
-
- point = [(LLNSWindow*)window convertRectToScreen:point];
-
- coord[0] = point.origin.x;
- coord[1] = point.origin.y;
- coord[2] = point.size.width;
- coord[3] = point.size.height;
+ NSRect rect = NSMakeRect(coord[0], coord[1], coord[2], coord[3]);;
+ rect = [(LLNSWindow*)window convertRectToScreen:rect];
+
+ coord[0] = rect.origin.x;
+ coord[1] = rect.origin.y;
+ coord[2] = rect.size.width;
+ coord[3] = rect.size.height;
}
void convertRectFromScreen(NSWindowRef window, float *coord)
{
- NSRect point;
- point.origin.x = coord[0];
- point.origin.y = coord[1];
- point.size.width = coord[2];
- point.size.height = coord[3];
-
- point = [(LLNSWindow*)window convertRectFromScreen:point];
-
- coord[0] = point.origin.x;
- coord[1] = point.origin.y;
- coord[2] = point.size.width;
- coord[3] = point.size.height;
-}
+ NSRect point = NSMakeRect(coord[0], coord[1], coord[2], coord[3]);
+ point = [(LLNSWindow*)window convertRectFromScreen:point];
-void convertScreenToView(NSWindowRef window, float *coord)
-{
- NSRect point;
- point.origin.x = coord[0];
- point.origin.y = coord[1];
- point.origin = [(LLNSWindow*)window convertScreenToBase:point.origin];
- point.origin = [[(LLNSWindow*)window contentView] convertPoint:point.origin fromView:nil];
+ coord[0] = point.origin.x;
+ coord[1] = point.origin.y;
+ coord[2] = point.size.width;
+ coord[3] = point.size.height;
}
void convertWindowToScreen(NSWindowRef window, float *coord)
{
- NSPoint point;
- point.x = coord[0];
- point.y = coord[1];
- point = [(LLNSWindow*)window convertToScreenFromLocalPoint:point relativeToView:[(LLNSWindow*)window contentView]];
- coord[0] = point.x;
- coord[1] = point.y;
+ NSRect rect = NSMakeRect(coord[0], coord[1], 0, 0);
+ rect = [(LLNSWindow*)window convertRectToScreen:rect];
+
+ coord[0] = rect.origin.x;
+ coord[1] = [[NSScreen screens][0] frame].size.height - rect.origin.y;
}
void closeWindow(NSWindowRef window)
{
- [(LLNSWindow*)window close];
- [(LLNSWindow*)window release];
+ [(LLNSWindow*)window close];
+ [(LLNSWindow*)window release];
}
void removeGLView(GLViewRef view)
{
- [(LLOpenGLView*)view clearGLContext];
- [(LLOpenGLView*)view removeFromSuperview];
+ [(LLOpenGLView*)view clearGLContext];
+ [(LLOpenGLView*)view removeFromSuperview];
}
void setupInputWindow(NSWindowRef window, GLViewRef glview)
{
- [[(LLAppDelegate*)[NSApp delegate] inputView] setGLView:(LLOpenGLView*)glview];
+ [[(LLAppDelegate*)[NSApp delegate] inputView] setGLView:(LLOpenGLView*)glview];
}
void commitCurrentPreedit(GLViewRef glView)
{
- [(LLOpenGLView*)glView commitCurrentPreedit];
+ [(LLOpenGLView*)glView commitCurrentPreedit];
}
void allowDirectMarkedTextInput(bool allow, GLViewRef glView)
@@ -401,20 +380,20 @@ void allowDirectMarkedTextInput(bool allow, GLViewRef glView)
NSWindowRef getMainAppWindow()
{
- LLNSWindow *winRef = [(LLAppDelegate*)[[NSApplication sharedApplication] delegate] window];
-
- [winRef setAcceptsMouseMovedEvents:TRUE];
- return winRef;
+ LLNSWindow *winRef = [(LLAppDelegate*)[[NSApplication sharedApplication] delegate] window];
+
+ [winRef setAcceptsMouseMovedEvents:TRUE];
+ return winRef;
}
void makeFirstResponder(NSWindowRef window, GLViewRef view)
{
- [(LLNSWindow*)window makeFirstResponder:(LLOpenGLView*)view];
+ [(LLNSWindow*)window makeFirstResponder:(LLOpenGLView*)view];
}
void requestUserAttention()
{
- [[NSApplication sharedApplication] requestUserAttention:NSInformationalRequest];
+ [[NSApplication sharedApplication] requestUserAttention:NSInformationalRequest];
}
long showAlert(std::string text, std::string title, int type)
@@ -422,7 +401,7 @@ long showAlert(std::string text, std::string title, int type)
long ret = 0;
@autoreleasepool {
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
-
+
[alert setMessageText:[NSString stringWithCString:title.c_str() encoding:[NSString defaultCStringEncoding]]];
[alert setInformativeText:[NSString stringWithCString:text.c_str() encoding:[NSString defaultCStringEncoding]]];
if (type == 0)
@@ -439,7 +418,7 @@ long showAlert(std::string text, std::string title, int type)
}
ret = [alert runModal];
}
-
+
if (ret == NSAlertFirstButtonReturn)
{
if (type == 1)
@@ -459,7 +438,7 @@ long showAlert(std::string text, std::string title, int type)
ret = 1;
}
}
-
+
return ret;
}
@@ -472,5 +451,5 @@ long showAlert(std::string text, std::string title, int type)
unsigned int getModifiers()
{
- return [NSEvent modifierFlags];
+ return [NSEvent modifierFlags];
}
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index c97e014e46..c0cc6596a2 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -38,21 +38,21 @@
#include "lldir.h"
#include "indra_constants.h"
-
#include <OpenGL/OpenGL.h>
#include <Carbon/Carbon.h>
#include <CoreServices/CoreServices.h>
#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>
#include <IOKit/usb/IOUSBLib.h>
extern bool gDebugWindowProc;
-bool gHiDPISupport = true;
+bool gHiDPISupport = false;
+bool gHDRDisplaySupport = false;
const S32 BITS_PER_PIXEL = 32;
const S32 MAX_NUM_RESOLUTIONS = 32;
@@ -166,6 +166,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
// Route them to a dummy callback structure until the end of constructor.
LLWindowCallbacks null_callbacks;
mCallbacks = &null_callbacks;
+ mIsConstructing = true;
// Voodoo for calling cocoa from carbon (see llwindowmacosx-objc.mm).
setupCocoa();
@@ -236,10 +237,11 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
allowLanguageTextInput(NULL, false);
}
+ setUseMultGL(sUseMultGL);
+
mCallbacks = callbacks;
+ mIsConstructing = false;
stop_glerror();
-
-
}
// These functions are used as wrappers for our internal event handling callbacks.
@@ -413,6 +415,14 @@ void callResize(unsigned int width, unsigned int height)
}
}
+void callRequestResolutionUpdate()
+{
+ if (gWindowImplementation && gWindowImplementation->getCallbacks())
+ {
+ gWindowImplementation->getCallbacks()->handleRequestResolutionUpdate(gWindowImplementation);
+ }
+}
+
void callMouseMoved(float *pos, MASK mask)
{
if (!gWindowImplementation)
@@ -611,7 +621,7 @@ void callQuitHandler()
{
if (gWindowImplementation && gWindowImplementation->getCallbacks())
{
- if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation))
+ if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation, true))
{
gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation);
}
@@ -706,6 +716,11 @@ void getPreeditLocation(float *location, unsigned int length)
}
}
+bool windowCallbacksReady()
+{
+ return gWindowImplementation && !gWindowImplementation->isConstructing();
+}
+
void LLWindowMacOSX::updateMouseDeltas(float* deltas)
{
if (mCursorDecoupled)
@@ -759,7 +774,7 @@ bool LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
kCGLPFAMultisample,
kCGLPFASampleBuffers, static_cast<CGLPixelFormatAttribute>((mFSAASamples > 0 ? 1 : 0)),
kCGLPFASamples, static_cast<CGLPixelFormatAttribute>(mFSAASamples),
- kCGLPFAStencilSize, static_cast<CGLPixelFormatAttribute>(8),
+ //kCGLPFAStencilSize, static_cast<CGLPixelFormatAttribute>(8),
kCGLPFADepthSize, static_cast<CGLPixelFormatAttribute>(24),
kCGLPFAAlphaSize, static_cast<CGLPixelFormatAttribute>(8),
kCGLPFAColorSize, static_cast<CGLPixelFormatAttribute>(24),
@@ -937,9 +952,10 @@ bool LLWindowMacOSX::getVisible()
if(mFullscreen)
{
result = true;
- }if (mWindow)
+ }
+ if (mWindow)
{
- result = true;
+ result = true;
}
return(result);
@@ -986,7 +1002,7 @@ bool LLWindowMacOSX::getPosition(LLCoordScreen *position)
}
else if(mWindow)
{
- const CGPoint & pos = getContentViewBoundsPosition(mWindow);
+ CGPoint pos = getContentViewRect(mWindow).origin;
position->mX = pos.x;
position->mY = pos.y;
@@ -1013,7 +1029,7 @@ bool LLWindowMacOSX::getSize(LLCoordScreen *size)
}
else if(mWindow)
{
- const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow);
+ CGSize sz = getBackingViewRect(mWindow, mGLView).size;
size->mX = sz.width;
size->mY = sz.height;
@@ -1039,7 +1055,7 @@ bool LLWindowMacOSX::getSize(LLCoordWindow *size)
}
else if(mWindow)
{
- const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow);
+ CGSize sz = getBackingViewRect(mWindow, mGLView).size;
size->mX = sz.width;
size->mY = sz.height;
@@ -1225,6 +1241,12 @@ void LLWindowMacOSX::setMouseClipping( bool b )
adjustCursorDecouple();
}
+#if LL_DARWIN
+// For CGSetLocalEventsSuppressionInterval there is no replacement in modern API
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position)
{
bool result = false;
@@ -1254,14 +1276,15 @@ bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position)
// trigger mouse move callback
LLCoordGL gl_pos;
convertCoords(position, &gl_pos);
- float scale = getSystemUISize();
- gl_pos.mX *= scale;
- gl_pos.mY *= scale;
mCallbacks->handleMouseMove(this, gl_pos, (MASK)0);
return result;
}
+#if LL_DARWIN
+#pragma clang diagnostic pop
+#endif
+
bool LLWindowMacOSX::getCursorPosition(LLCoordWindow *position)
{
float cursor_point[2];
@@ -1486,8 +1509,9 @@ bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to)
convertScreenToWindow(mWindow, mouse_point);
- to->mX = mouse_point[0];
- to->mY = mouse_point[1];
+ float scale_factor = getSystemUISize();
+ to->mX = mouse_point[0] * scale_factor;
+ to->mY = mouse_point[1] * scale_factor;
return true;
}
@@ -1499,9 +1523,9 @@ bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to)
if(mWindow)
{
float mouse_point[2];
-
- mouse_point[0] = from.mX;
- mouse_point[1] = from.mY;
+ float scale_factor = getSystemUISize();
+ mouse_point[0] = from.mX / scale_factor;
+ mouse_point[1] = from.mY / scale_factor;
convertWindowToScreen(mWindow, mouse_point);
@@ -2372,7 +2396,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;
@@ -2626,6 +2650,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)
{
@@ -2638,7 +2668,7 @@ MASK LLWindowMacOSX::modifiersToMask(S16 modifiers)
F32 LLWindowMacOSX::getSystemUISize()
{
- return gHiDPISupport ? ::getDeviceUnitSize(mGLView) : LLWindow::getSystemUISize();
+ return ::getDeviceUnitSize(mGLView);
}
#if LL_OS_DRAGDROP_ENABLED
diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h
index 7de1a40d93..a9475c84cc 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:
@@ -55,7 +50,11 @@ public:
void restore() override;
bool getFullscreen();
bool getPosition(LLCoordScreen *position) override;
+
+ // Content view size in backing pixels (excludes title bar).
+ // Note: on Windows, getSize(LLCoordScreen) returns the outer window frame size (includes title bar and borders).
bool getSize(LLCoordScreen *size) override;
+
bool getSize(LLCoordWindow *size) override;
bool setPosition(LLCoordScreen position) override;
bool setSizeImpl(LLCoordScreen size) override;
@@ -63,6 +62,7 @@ public:
bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) override;
bool setCursorPosition(LLCoordWindow position) override;
bool getCursorPosition(LLCoordWindow *position) override;
+ bool isWrapMouse() const override { return !mCursorDecoupled; };
void showCursor() override;
void hideCursor() override;
void showCursorFromMouseMove() override;
@@ -121,6 +121,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;
@@ -150,6 +151,10 @@ public:
// enable or disable multithreaded GL
static void setUseMultGL(bool use_mult_gl);
+ // During construction null_callbacks are used,
+ // this is a way to determine when callbacks are ready.
+ bool isConstructing() const { return mIsConstructing; }
+
protected:
LLWindowMacOSX(LLWindowCallbacks* callbacks,
const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
@@ -174,9 +179,6 @@ protected:
bool shouldPostQuit() { return mPostQuit; }
- //Satisfy MAINT-3135 and MAINT-3288 with a flag.
- /*virtual */ void setOldResize(bool oldresize) override {setResizeMode(oldresize, mGLView); }
-
private:
void restoreGLContext();
@@ -229,6 +231,7 @@ protected:
bool mMinimized;
U32 mFSAASamples;
bool mForceRebuild;
+ bool mIsConstructing = true;
S32 mDragOverrideCursor;
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 69332e36b6..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,108 +49,48 @@ 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
// TOFU HACK -- (*exactly* the same hack as LLWindowMacOSX for a similar
// set of reasons): Stash a pointer to the LLWindowSDL object here and
// maintain in the constructor and destructor. This assumes that there will
// be only one object of this class at any time. Currently this is true.
-static LLWindowSDL *gWindowImplementation = NULL;
-
-
-void maybe_lock_display(void)
-{
- if (gWindowImplementation && gWindowImplementation->Lock_Display) {
- gWindowImplementation->Lock_Display();
- }
-}
-
-
-void maybe_unlock_display(void)
-{
- if (gWindowImplementation && gWindowImplementation->Unlock_Display) {
- gWindowImplementation->Unlock_Display();
- }
-}
-
-
-#if LL_X11
-// static
-Window LLWindowSDL::get_SDL_XWindowID(void)
-{
- if (gWindowImplementation) {
- return gWindowImplementation->mSDL_XWindowID;
- }
- return None;
-}
-
-//static
-Display* LLWindowSDL::get_SDL_Display(void)
-{
- if (gWindowImplementation) {
- return gWindowImplementation->mSDL_Display;
- }
- return NULL;
-}
-#endif // LL_X11
+static LLWindowSDL *gWindowImplementation = nullptr;
LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks,
const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
@@ -156,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";
@@ -195,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
@@ -206,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)
@@ -239,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
@@ -247,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;
@@ -279,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;
@@ -289,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;
@@ -353,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};
@@ -375,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);
@@ -412,56 +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;
- mFullscreenBits = mSurface->format->BitsPerPixel;
- */
- 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
- << "x" << mFullscreenBits
- << " @ " << 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;
- mFullscreenBits = -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);
@@ -479,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"
@@ -495,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;
@@ -503,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)
@@ -609,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);
}
}
@@ -633,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
@@ -650,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
@@ -689,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;
}
@@ -712,6 +600,7 @@ void LLWindowSDL::show()
if (mWindow)
{
SDL_ShowWindow(mWindow);
+ SDL_RaiseWindow(mWindow);
}
}
@@ -723,7 +612,6 @@ void LLWindowSDL::hide()
}
}
-//virtual
void LLWindowSDL::minimize()
{
if (mWindow)
@@ -732,7 +620,6 @@ void LLWindowSDL::minimize()
}
}
-//virtual
void LLWindowSDL::restore()
{
if (mWindow)
@@ -745,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();
@@ -760,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;
@@ -782,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;
@@ -796,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;
@@ -816,11 +697,6 @@ bool LLWindowSDL::maximize()
return false;
}
-bool LLWindowSDL::getFullscreen()
-{
- return mFullscreen;
-}
-
bool LLWindowSDL::getPosition(LLCoordScreen *position)
{
if (mWindow)
@@ -835,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)
@@ -877,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;
}
@@ -932,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;
}
@@ -945,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;
}
@@ -965,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
@@ -981,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)
@@ -1011,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()
@@ -1073,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)
@@ -1144,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)
@@ -1167,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)
@@ -1193,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)
@@ -1203,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);
}
}
@@ -1236,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;
}
@@ -1254,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;
}
@@ -1270,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)
@@ -1281,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);
}
@@ -1331,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
@@ -1346,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;
@@ -1395,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))
- {
- // 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)
@@ -1757,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;
@@ -1787,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];
@@ -1810,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;
}
@@ -1844,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);
@@ -1902,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;
}
}
@@ -1947,7 +1690,7 @@ void LLWindowSDL::hideCursor()
// LL_INFOS() << "hideCursor: hiding" << LL_ENDL;
mCursorHidden = true;
mHideCursorPermanent = true;
- SDL_ShowCursor(SDL_DISABLE);
+ SDL_HideCursor();
}
else
{
@@ -1962,7 +1705,7 @@ void LLWindowSDL::showCursor()
// LL_INFOS() << "showCursor: showing" << LL_ENDL;
mCursorHidden = false;
mHideCursorPermanent = false;
- SDL_ShowCursor(SDL_ENABLE);
+ SDL_ShowCursor();
}
else
{
@@ -2038,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
@@ -2083,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.
@@ -2124,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;
}
@@ -2132,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()
@@ -2151,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)
@@ -2260,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 144216f658..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__)
-#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,86 +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;
@@ -185,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,
@@ -230,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
@@ -250,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
@@ -302,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 4fca74497f..ab857fa58d 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -49,6 +49,7 @@
#include "llthreadsafequeue.h"
#include "stringize.h"
#include "llframetimer.h"
+#include "llwatchdog.h"
// System includes
#include <commdlg.h>
@@ -64,6 +65,7 @@
#include <utility> // std::pair
#include <d3d9.h>
+#include <d3d11.h>
#include <dxgi1_4.h>
#include <timeapi.h>
@@ -76,6 +78,11 @@
#pragma comment(lib, "dxguid.lib") // needed for llurlentry test to build on some systems
#pragma comment(lib, "dinput8")
+#pragma comment(lib, "UxTheme.lib")
+#pragma comment(lib, "Dwmapi.lib")
+#include <Uxtheme.h>
+#include <dwmapi.h> // needed for DwmSetWindowAttribute to set window theme
+
const S32 MAX_MESSAGE_PER_UPDATE = 20;
const S32 BITS_PER_PIXEL = 32;
const S32 MAX_NUM_RESOLUTIONS = 32;
@@ -85,6 +92,10 @@ const F32 ICON_FLASH_TIME = 0.5f;
#define USER_DEFAULT_SCREEN_DPI 96 // Win7
#endif
+#ifndef WM_DWMCOLORIZATIONCOLORCHANGED
+#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320
+#endif
+
// Claim a couple unused GetMessage() message IDs
const UINT WM_DUMMY_(WM_USER + 0x0017);
const UINT WM_POST_FUNCTION_(WM_USER + 0x0018);
@@ -104,7 +115,16 @@ static std::thread::id sMainThreadId;
LPWSTR gIconResource = IDI_APPLICATION;
-LPDIRECTINPUT8 gDirectInput8;
+LPWSTR gIconSmallResource = IDI_APPLICATION;
+
+namespace
+{
+ LPDIRECTINPUT8 gDirectInput8;
+ ID3D11Device* gD3D11Device = nullptr;
+ ID3D11DeviceContext* gD3D11Context = nullptr;
+ LUID gExpectedAdapterLUID;
+ HMODULE gD3D11Library;
+}
LLW32MsgCallback gAsyncMsgCallback = NULL;
@@ -137,6 +157,17 @@ typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)(
_Out_ UINT *dpiX,
_Out_ UINT *dpiY);
+typedef enum PREFERRED_APP_MODE
+{
+ DEFAULT,
+ ALLOW_DARK,
+ FORCE_DARK,
+ FORCE_LIGHT,
+ MAX
+} PREFERRED_APP_MODE;
+
+typedef PREFERRED_APP_MODE(WINAPI* fnSetPreferredAppMode)(PREFERRED_APP_MODE mode);
+
//
// LLWindowWin32
//
@@ -146,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
@@ -183,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;
@@ -343,17 +388,22 @@ static LLMonitorInfo sMonitorInfo;
// the containing class a friend.
struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
{
- static const int MAX_QUEUE_SIZE = 2048;
+ static constexpr int MAX_QUEUE_SIZE = 2048;
+ static constexpr F32 WINDOW_TIMEOUT_SEC = 90.f;
LLThreadSafeQueue<MSG> mMessageQueue;
LLWindowWin32Thread();
void run() override;
- void close() override;
- // closes queue, wakes thread, waits until thread closes
- void wakeAndDestroy();
+ // Detroys handles and window
+ // Either post to or call from window thread
+ void destroyWindow();
+
+ // Closes queue, wakes thread, waits until thread closes.
+ // Call from main thread
+ bool wakeAndDestroy();
void glReady()
{
@@ -401,6 +451,60 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
PostMessage(windowHandle, WM_POST_FUNCTION_, wparam, LPARAM(ptr));
}
+ // Call from main thread.
+ void initTimeout()
+ {
+ // post into thread's queue to avoid threading issues
+ post([this]()
+ {
+ if (!mWindowTimeout)
+ {
+ mWindowTimeout = std::make_unique<LLWatchdogTimeout>("WindowThread");
+ // supposed to be executed within run(),
+ // so no point checking if thread is alive
+ resumeTimeout("TimeoutInit");
+ }
+ });
+ }
+
+ // For mainWindowProc, it should not unpause watchdog if it was paused
+ void pingWindowTimeout(std::string_view state)
+ {
+ if (mWindowTimeout && mWindowTimeout->started())
+ {
+ mWindowTimeout->setTimeout(WINDOW_TIMEOUT_SEC);
+ mWindowTimeout->ping(state);
+ }
+ }
+private:
+ // These timeout related functions are strictly for the thread.
+ void resumeTimeout(std::string_view state)
+ {
+ if (mWindowTimeout)
+ {
+ mWindowTimeout->setTimeout(WINDOW_TIMEOUT_SEC);
+ mWindowTimeout->start(state);
+ }
+ }
+
+ void pauseTimeout()
+ {
+ if (mWindowTimeout)
+ {
+ mWindowTimeout->stop();
+ }
+ }
+
+ void pingTimeout(std::string_view state)
+ {
+ if (mWindowTimeout)
+ {
+ mWindowTimeout->setTimeout(WINDOW_TIMEOUT_SEC);
+ mWindowTimeout->ping(state);
+ }
+ }
+
+public:
using FuncType = std::function<void()>;
// call GetMessage() and pull enqueue messages for later processing
HWND mWindowHandleThrd = NULL;
@@ -410,6 +514,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
// until after some graphics setup. See SL-20177. -Cosmic,2023-09-18
bool mGLReady = false;
bool mGotGLBuffer = false;
+ LLAtomicBool mDeleteOnExit = false;
+private:
+ std::unique_ptr<LLWatchdogTimeout> mWindowTimeout;
};
@@ -424,6 +531,8 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
F32 max_gl_version)
:
LLWindow(callbacks, fullscreen, flags),
+ mAbsoluteCursorPosition(false),
+ mReceivedSCClose(false),
mMaxGLVersion(max_gl_version),
mMaxCores(max_cores)
{
@@ -431,8 +540,12 @@ 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
+ // the context is created.
+ requestHighPerformanceGPU();
if (mMaxCores != 0)
{
@@ -448,6 +561,8 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
SetProcessAffinityMask(hProcess, mask);
}
+ setThreadPriorityHigh();
+
#if 0 // this is probably a bad idea, but keep it in your back pocket if you see what looks like
// process deprioritization during profiles
// force high thread priority
@@ -470,43 +585,9 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
}
#endif
-#if 0 // this is also probably a bad idea, but keep it in your back pocket for getting main thread off of background thread cores (see also LLThread::threadRun)
- HANDLE hThread = GetCurrentThread();
-
- SYSTEM_INFO sysInfo;
-
- GetSystemInfo(&sysInfo);
- U32 core_count = sysInfo.dwNumberOfProcessors;
-
- if (max_cores != 0)
- {
- core_count = llmin(core_count, max_cores);
- }
-
- if (hThread)
- {
- int priority = GetThreadPriority(hThread);
-
- if (priority < THREAD_PRIORITY_TIME_CRITICAL)
- {
- if (SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL))
- {
- LL_INFOS() << "Set thread priority to THREAD_PRIORITY_TIME_CRITICAL" << LL_ENDL;
- }
- else
- {
- LL_INFOS() << "Failed to set thread priority: " << std::hex << GetLastError() << LL_ENDL;
- }
-
- // tell main thread to prefer core 0
- SetThreadIdealProcessor(hThread, 0);
- }
- }
-#endif
-
-
mFSAASamples = fsaa_samples;
mIconResource = gIconResource;
+ mIconSmallResource = gIconSmallResource;
mOverrideAspectRatio = 0.f;
mNativeAspectRatio = 0.f;
mInputProcessingPaused = false;
@@ -576,6 +657,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
// Make an instance of our window then define the window class
mhInstance = GetModuleHandle(NULL);
+#if !_M_ARM64
// Init Direct Input - needed for joystick / Spacemouse
LPDIRECTINPUT8 di8_interface;
@@ -590,6 +672,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
{
gDirectInput8 = di8_interface;
}
+#endif
mSwapMethod = SWAP_METHOD_UNDEFINED;
@@ -695,8 +778,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
}
if (dev_mode.dmPelsWidth == width &&
- dev_mode.dmPelsHeight == height &&
- dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
+ dev_mode.dmPelsHeight == height)
{
success = true;
if ((dev_mode.dmDisplayFrequency - current_refresh)
@@ -736,7 +818,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
// If we found a good resolution, use it.
if (success)
{
- success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
+ success = setDisplayResolution(width, height, closest_refresh);
}
// Keep a copy of the actual current device mode in case we minimize
@@ -749,7 +831,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
mFullscreen = true;
mFullscreenWidth = dev_mode.dmPelsWidth;
mFullscreenHeight = dev_mode.dmPelsHeight;
- mFullscreenBits = dev_mode.dmBitsPerPel;
mFullscreenRefresh = dev_mode.dmDisplayFrequency;
LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
@@ -763,7 +844,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
mFullscreen = false;
mFullscreenWidth = -1;
mFullscreenHeight = -1;
- mFullscreenBits = -1;
mFullscreenRefresh = -1;
std::map<std::string,std::string> args;
@@ -786,7 +866,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
// }
// SL-12971 dual GPU display
- DISPLAY_DEVICEA display_device;
+ DISPLAY_DEVICE display_device;
int display_index = -1;
DWORD display_flags = 0; // EDD_GET_DEVICE_INTERFACE_NAME ?
const size_t display_bytes = sizeof(display_device);
@@ -797,23 +877,23 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
{
// CHAR DeviceName [ 32] Adapter name
// CHAR DeviceString[128]
- CHAR text[256];
+ WCHAR text[256];
- size_t name_len = strlen(display_device.DeviceName );
- size_t desc_len = strlen(display_device.DeviceString);
+ size_t name_len = lstrlen(display_device.DeviceName );
+ size_t desc_len = lstrlen(display_device.DeviceString);
- const CHAR *name = name_len ? display_device.DeviceName : "???";
- const CHAR *desc = desc_len ? display_device.DeviceString : "???";
+ const WCHAR *name = name_len ? display_device.DeviceName : TEXT("???");
+ const WCHAR *desc = desc_len ? display_device.DeviceString : TEXT("???");
- sprintf(text, "Display Device %d: %s, %s", display_index, name, desc);
- LL_INFOS("Window") << text << LL_ENDL;
+ wsprintf(text, TEXT("Display Device %d: %s, %s"), display_index, name, desc);
+ LL_INFOS("Window") << ll_convert<std::string>(std::wstring(text)) << LL_ENDL;
}
::ZeroMemory(&display_device,display_bytes);
display_device.cb = display_bytes;
display_index++;
- } while( EnumDisplayDevicesA(NULL, display_index, &display_device, display_flags ));
+ } while( EnumDisplayDevices(NULL, display_index, &display_device, display_flags ));
LL_INFOS("Window") << "Total Display Devices: " << display_index << LL_ENDL;
@@ -842,6 +922,8 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
// Initialize (boot strap) the Language text input management,
// based on the system's (or user's) default settings.
allowLanguageTextInput(NULL, false);
+ updateWindowTheme();
+ setCustomIcon();
}
@@ -853,6 +935,7 @@ LLWindowWin32::~LLWindowWin32()
}
delete mDragDrop;
+ mDragDrop = NULL;
delete [] mWindowTitle;
mWindowTitle = NULL;
@@ -864,6 +947,7 @@ LLWindowWin32::~LLWindowWin32()
mWindowClassName = NULL;
delete mWindowThread;
+ mWindowThread = NULL;
}
void LLWindowWin32::show()
@@ -930,6 +1014,7 @@ void LLWindowWin32::close()
}
mDragDrop->reset();
+ clearHighPerformanceGPURequest();
// Go back to screen mode written in the registry.
@@ -972,7 +1057,7 @@ void LLWindowWin32::close()
// Restore gamma to the system values.
restoreGamma();
- LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
+ LL_INFOS("Window") << "Cleanup and destruction of Window Thread" << LL_ENDL;
if (sWindowHandleForMessageBox == mWindowHandle)
{
@@ -982,7 +1067,11 @@ void LLWindowWin32::close()
mhDC = NULL;
mWindowHandle = NULL;
- mWindowThread->wakeAndDestroy();
+ if (mWindowThread->wakeAndDestroy())
+ {
+ // thread will delete itselfs once done
+ mWindowThread = NULL;
+ }
}
bool LLWindowWin32::isValid()
@@ -990,6 +1079,52 @@ bool LLWindowWin32::isValid()
return (mWindowHandle != NULL);
}
+void LLWindowWin32::setThreadPriorityHigh()
+{
+ // Threads start at normal priority. But this is our main window/rendering thread,
+ // even if window handle belongs to another thread. So we can raise its priority
+ // to ensure better responsiveness and less blocking by lack of resources.
+ HANDLE hThread = GetCurrentThread();
+ if (hThread)
+ {
+ int priority = GetThreadPriority(hThread);
+
+ if (priority == THREAD_PRIORITY_ERROR_RETURN)
+ {
+ LL_WARNS_ONCE("Window") << "Failed to get thread priority: " << std::hex << GetLastError() << LL_ENDL;
+ }
+ else if (priority > THREAD_PRIORITY_HIGHEST)
+ {
+ // At the moment nothing should be setting 'critical' priority,
+ // but if that happens for some reason, we don't want to mess with it.
+ LL_WARNS("Window") << "setThreadPriorityHigh ignored, priority was " << (S32)priority << LL_ENDL;
+ }
+ else if (priority != THREAD_PRIORITY_HIGHEST)
+ {
+ if (SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST))
+ {
+ LL_DEBUGS("Window") << "Set thread priority to THREAD_PRIORITY_HIGHEST" << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS("Window") << "Failed to set thread priority: " << std::hex << GetLastError() << LL_ENDL;
+ }
+ }
+ }
+}
+
+void LLWindowWin32::setThreadPriorityNormal()
+{
+ HANDLE hThread = GetCurrentThread();
+ if (hThread)
+ {
+ if (!SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL))
+ {
+ LL_WARNS_ONCE("Window") << "Failed to set thread priority: " << std::hex << GetLastError() << LL_ENDL;
+ }
+ }
+}
+
bool LLWindowWin32::getVisible()
{
return (mWindowHandle && IsWindowVisible(mWindowHandle));
@@ -1185,7 +1320,7 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
// If we found a good resolution, use it.
if (success)
{
- success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
+ success = setDisplayResolution(width, height, closest_refresh);
}
// Keep a copy of the actual current device mode in case we minimize
@@ -1197,7 +1332,6 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
mFullscreen = true;
mFullscreenWidth = dev_mode.dmPelsWidth;
mFullscreenHeight = dev_mode.dmPelsHeight;
- mFullscreenBits = dev_mode.dmBitsPerPel;
mFullscreenRefresh = dev_mode.dmDisplayFrequency;
LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
@@ -1223,7 +1357,6 @@ bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bo
mFullscreen = false;
mFullscreenWidth = -1;
mFullscreenHeight = -1;
- mFullscreenBits = -1;
mFullscreenRefresh = -1;
LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL;
@@ -1314,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;
}
@@ -1325,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;
}
@@ -1363,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;
}
@@ -1371,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;
}
@@ -1584,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;
}
@@ -1623,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;
}
@@ -1632,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;
}
@@ -1654,18 +1787,25 @@ 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;
}
+ // Setup Tracy gpu context
+ {
+ LL_PROFILER_GPU_CONTEXT;
+ }
+
// Disable vertical sync for swap
toggleVSync(enable_vsync);
@@ -1697,8 +1837,6 @@ const S32 max_format = (S32)num_formats - 1;
swapBuffers();
}
- LL_PROFILER_GPU_CONTEXT;
-
return true;
}
@@ -1866,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;
@@ -1931,7 +2069,7 @@ void LLWindowWin32::setTitle(const std::string title)
// to support non-ascii usernames (and region names?)
mWindowThread->post([=]()
{
- SetWindowTextA(mWindowHandle, title.c_str());
+ SetWindowText(mWindowHandle, ll_convert<std::wstring>(title).c_str());
});
}
@@ -2304,18 +2442,45 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
case WM_DEVICECHANGE:
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DEVICECHANGE");
+ window_imp->mWindowThread->pingWindowTimeout("WM_DEVICECHANGE");
+
+ // Log detailed device change information
+ std::string change_type = "UNKNOWN";
+ switch (w_param)
+ {
+ case DBT_DEVICEARRIVAL: change_type = "DBT_DEVICEARRIVAL"; break;
+ case DBT_DEVICEREMOVECOMPLETE: change_type = "DBT_DEVICEREMOVECOMPLETE"; break;
+ case DBT_DEVNODES_CHANGED: change_type = "DBT_DEVNODES_CHANGED"; break;
+ case DBT_DEVICEQUERYREMOVE: change_type = "DBT_DEVICEQUERYREMOVE"; break;
+ case DBT_DEVICEQUERYREMOVEFAILED: change_type = "DBT_DEVICEQUERYREMOVEFAILED"; break;
+ case DBT_DEVICEREMOVEPENDING: change_type = "DBT_DEVICEREMOVEPENDING"; break;
+ case DBT_CONFIGCHANGED: change_type = "DBT_CONFIGCHANGED"; break;
+ }
+
if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL)
{
- WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp));
+ WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp, change_type));
return 1;
}
+ else if (l_param)
+ {
+ const auto* hdr = reinterpret_cast<const DEV_BROADCAST_HDR*>(l_param);
+ if (hdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
+ {
+ // Might need to register for monitor device notifications
+ // to get this message when monitor is suspended or resumed.
+ // TODO: log monitor suspending and resuming.
+ LL_INFOS("Window") << "DEVICEINTERFACE: " << change_type << LL_ENDL;
+ }
+ }
break;
}
case WM_PAINT:
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_PAINT");
+ window_imp->mWindowThread->pingWindowTimeout("WM_PAINT");
GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE);
update_width = update_rect.right - update_rect.left + 1;
update_height = update_rect.bottom - update_rect.top + 1;
@@ -2324,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;
@@ -2361,11 +2535,24 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
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)
+ {
+ return;
+ }
+
if (window_imp->mFullscreen)
{
// When we run fullscreen, restoring or minimizing the app needs
@@ -2415,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;
@@ -2431,10 +2625,35 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
case WM_CLOSE:
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CLOSE");
+ window_imp->mWindowThread->pingWindowTimeout("WM_CLOSE");
+
+ 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?
- if (window_imp->mCallbacks->handleCloseRequest(window_imp))
+ if (window_imp->mCallbacks->handleCloseRequest(window_imp, true))
{
// Get the app to initiate cleanup.
window_imp->mCallbacks->handleQuit(window_imp);
@@ -2452,6 +2671,247 @@ 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.
+ // Can use ShutdownBlockReasonCreate here.
+ LL_INFOS("Window") << "Received WM_QUERYENDSESSION with wParam: " << (U32)w_param << " lParam: " << (U32)l_param << LL_ENDL;
+ return TRUE; // 1 = ok to end session. 0 no longer works by itself, use ShutdownBlockReasonCreate
+ }
+ case WM_ENDSESSION:
+ {
+ // OS session is shutting down, initiate cleanup.
+ // Comes after WM_QUERYENDSESSION
+ LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ENDSESSION");
+ LL_INFOS("Window") << "Received WM_ENDSESSION with wParam: " << (U32)w_param << " lParam: " << (U32)l_param << LL_ENDL;
+ window_imp->mWindowThread->pingWindowTimeout("WM_ENDSESSION");
+ unsigned int end_session_flags = (U32)l_param;
+
+ if (w_param == TRUE // if true, session is ending
+ || end_session_flags == 0 // not possible to determine type of the event
+ // || (end_session_flags & ENDSESSION_CLOSEAPP)) system update or low resources, must be acompanied by w_param == TRUE
+ || (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))
+ {
+ // Get the app to initiate cleanup.
+ window_imp->mCallbacks->handleQuit(window_imp);
+ }
+ });
+ // Give app a second to finish up. That's not enough for a clean exit,
+ // but better than nothing.
+ // Todo: sync this better, some kind of waitForResult? Can't wait forever,
+ // but for ENDSESSION_LOGOFF can potentially use ShutdownBlockReasonCreate
+ // for a bigger delay.
+ ms_sleep(1000);
+ }
+ // Don't need to post quit or destroy window,
+ // 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");
@@ -2915,19 +3375,31 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
// means that the window was un-minimized.
if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED)
{
- WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, true));
+ window_imp->post([=]()
+ {
+ window_imp->setThreadPriorityHigh();
+ window_imp->mCallbacks->handleActivate(window_imp, true);
+ });
}
// handle case of window being maximized from fully minimized state
if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED)
{
- WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, true));
+ window_imp->post([=]()
+ {
+ window_imp->setThreadPriorityHigh();
+ window_imp->mCallbacks->handleActivate(window_imp, true);
+ });
}
// Also handle the minimization case
if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED)
{
- WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, false));
+ window_imp->post([=]()
+ {
+ window_imp->setThreadPriorityNormal();
+ window_imp->mCallbacks->handleActivate(window_imp, false);
+ });
}
// Actually resize all of our views
@@ -2947,6 +3419,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
case WM_DPICHANGED:
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DPICHANGED");
+ window_imp->mWindowThread->pingWindowTimeout("WM_DPICHANGED");
LPRECT lprc_new_scale;
F32 new_scale = F32(LOWORD(w_param)) / F32(USER_DEFAULT_SCREEN_DPI);
lprc_new_scale = (LPRECT)l_param;
@@ -2967,7 +3440,19 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
case WM_DISPLAYCHANGE:
{
- WINDOW_IMP_POST(window_imp->mCallbacks->handleDisplayChanged());
+ LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DISPLAYCHANGE");
+ window_imp->mWindowThread->pingWindowTimeout("WM_DISPLAYCHANGE");
+ 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:
@@ -3005,6 +3490,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
case WM_SETTINGCHANGE:
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETTINGCHANGE");
+ // Can be called on OS user switching
+ LL_INFOS("Window") << "WM_SETTINGCHANGE, with wParam: 0x" << std::hex << (uintptr_t)w_param << " lParam: 0x" << (uintptr_t)l_param << std::dec << LL_ENDL;
+ window_imp->mWindowThread->pingWindowTimeout("WM_SETTINGCHANGE");
if (w_param == SPI_SETMOUSEVANISH)
{
if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &window_imp->mMouseVanish, 0))
@@ -3012,6 +3500,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
WINDOW_IMP_POST(window_imp->mMouseVanish = true);
}
}
+ // Check if theme-related settings changed
+ else if (l_param && (wcscmp((LPCWSTR)l_param, L"ImmersiveColorSet") == 0))
+ {
+ WINDOW_IMP_POST(window_imp->updateWindowTheme());
+ }
+ }
+ break;
+
+ case WM_DWMCOLORIZATIONCOLORCHANGED:
+ {
+ WINDOW_IMP_POST(window_imp->updateWindowTheme());
}
break;
@@ -3065,6 +3564,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
prev_absolute_x = absolute_x;
prev_absolute_y = absolute_y;
+ window_imp->mAbsoluteCursorPosition = true;
}
else
{
@@ -3081,6 +3581,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
window_imp->mRawMouseDelta.mX += (S32)round((F32)raw->data.mouse.lLastX * (F32)speed / DEFAULT_SPEED);
window_imp->mRawMouseDelta.mY -= (S32)round((F32)raw->data.mouse.lLastY * (F32)speed / DEFAULT_SPEED);
}
+ window_imp->mAbsoluteCursorPosition = false;
}
}
}
@@ -3104,10 +3605,14 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
break;
}
}
- else
+ else // (NULL == window_imp)
{
- // (NULL == window_imp)
LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL;
+ if (u_msg == WM_DESTROY)
+ {
+ PostQuitMessage(0); // Posts WM_QUIT with an exit code of 0
+ return 0;
+ }
}
// pass unhandled messages down to Windows
@@ -3241,7 +3746,7 @@ bool LLWindowWin32::pasteTextFromClipboard(LLWString &dst)
WCHAR *utf16str = (WCHAR*) GlobalLock(h_data);
if (utf16str)
{
- dst = utf16str_to_wstring(utf16str);
+ dst = ll_convert<LLWString>(std::wstring(utf16str));
LLWStringUtil::removeWindowsCR(dst);
GlobalUnlock(h_data);
success = true;
@@ -3266,8 +3771,8 @@ bool LLWindowWin32::copyTextToClipboard(const LLWString& wstr)
// Provide a copy of the data in Unicode format.
LLWString sanitized_string(wstr);
LLWStringUtil::addCRLF(sanitized_string);
- llutf16string out_utf16 = wstring_to_utf16str(sanitized_string);
- const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR);
+ std::wstring out_utf16 = ll_convert<std::wstring>(sanitized_string);
+ const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(wchar_t);
// Memory is allocated and then ownership of it is transfered to the system.
HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16);
@@ -3517,7 +4022,7 @@ F32 LLWindowWin32::getPixelAspectRatio()
// Change display resolution. Returns true if successful.
// protected
-bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh)
+bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 refresh)
{
DEVMODE dev_mode;
::ZeroMemory(&dev_mode, sizeof(DEVMODE));
@@ -3529,7 +4034,6 @@ bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re
{
if (dev_mode.dmPelsWidth == width &&
dev_mode.dmPelsHeight == height &&
- dev_mode.dmBitsPerPel == bits &&
dev_mode.dmDisplayFrequency == refresh )
{
// ...display mode identical, do nothing
@@ -3541,9 +4045,8 @@ bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re
dev_mode.dmSize = sizeof(dev_mode);
dev_mode.dmPelsWidth = width;
dev_mode.dmPelsHeight = height;
- dev_mode.dmBitsPerPel = bits;
dev_mode.dmDisplayFrequency = refresh;
- dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
+ dev_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
// CDS_FULLSCREEN indicates that this is a temporary change to the device mode.
LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN);
@@ -3553,7 +4056,7 @@ bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re
if (!success)
{
LL_WARNS("Window") << "setDisplayResolution failed, "
- << width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL;
+ << width << "x" << height << " @ " << refresh << LL_ENDL;
}
return success;
@@ -3564,7 +4067,7 @@ bool LLWindowWin32::setFullscreenResolution()
{
if (mFullscreen)
{
- return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh);
+ return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenRefresh);
}
else
{
@@ -3629,7 +4132,7 @@ void LLSplashScreenWin32::showImpl()
ShowWindow(mWindow, SW_SHOW);
// Should set taskbar text without creating a header for the window (caption)
- SetWindowTextA(mWindow, "Second Life");
+ SetWindowText(mWindow, TEXT("Second Life"));
}
@@ -3766,8 +4269,7 @@ void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async)
// reliablly on Vista.
// this is madness.. no, this is..
- LLWString url_wstring = utf8str_to_wstring( escaped_url );
- llutf16string url_utf16 = wstring_to_utf16str( url_wstring );
+ std::wstring url_utf16 = ll_convert<std::wstring>(escaped_url);
// let the OS decide what to use to open the URL
SHELLEXECUTEINFO sei = { sizeof( sei ) };
@@ -4055,7 +4557,7 @@ void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont)
U32 LLWindowWin32::fillReconvertString(const LLWString &text,
S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string)
{
- const llutf16string text_utf16 = wstring_to_utf16str(text);
+ const std::wstring text_utf16 = ll_convert<std::wstring>(text);
const DWORD required_size = sizeof(RECONVERTSTRING) + (static_cast<DWORD>(text_utf16.length()) + 1) * sizeof(WCHAR);
if (reconvert_string && reconvert_string->dwSize >= required_size)
{
@@ -4155,7 +4657,7 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes)
size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size);
if (size > 0)
{
- result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR)));
+ result_string = ll_convert_wide_to_wstring(std::wstring(data, size / sizeof(WCHAR)));
}
delete[] data;
needs_update = true;
@@ -4172,7 +4674,7 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes)
if (size > 0)
{
preedit_string_utf16_length = size / sizeof(WCHAR);
- preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR)));
+ preedit_string = ll_convert_wide_to_wstring(std::wstring(data, size / sizeof(WCHAR)));
}
delete[] data;
needs_update = true;
@@ -4478,6 +4980,248 @@ void LLWindowWin32::setDPIAwareness()
}
}
+void LLWindowWin32::requestHighPerformanceGPU() const
+{
+ // Try to load d3d11.dll and request high performance adapter
+ gD3D11Library = LoadLibraryA("d3d11.dll");
+ if (gD3D11Library)
+ {
+ typedef HRESULT(WINAPI* PFN_D3D11_CREATE_DEVICE)(
+ IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT,
+ const D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**,
+ D3D_FEATURE_LEVEL*, ID3D11DeviceContext**);
+
+ PFN_D3D11_CREATE_DEVICE pD3D11CreateDevice =
+ (PFN_D3D11_CREATE_DEVICE)GetProcAddress(gD3D11Library, "D3D11CreateDevice");
+
+ if (pD3D11CreateDevice)
+ {
+ // Try to enumerate adapters and select the best one
+ IDXGIFactory1* pFactory = nullptr;
+ IDXGIAdapter1* pSelectedAdapter = nullptr;
+ std::string selected_descr;
+ HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory);
+
+ if (SUCCEEDED(hr) && pFactory)
+ {
+ IDXGIAdapter1* pAdapter = nullptr;
+ SIZE_T maxDedicatedMemory = 0;
+ UINT adapterIndex = 0;
+ S32 adapter_count = 0;
+
+ // Enumerate all adapters and find the one with the most dedicated video memory
+ while (pFactory->EnumAdapters1(adapterIndex, &pAdapter) != DXGI_ERROR_NOT_FOUND)
+ {
+ DXGI_ADAPTER_DESC1 desc;
+ pAdapter->GetDesc1(&desc);
+
+ std::wstring description_w(desc.Description);
+ std::string description = ll_convert_wide_to_string(description_w);
+
+
+ // Skip software adapters
+ if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
+ {
+ LL_DEBUGS("Window") << "Adapter " << adapterIndex << ": " << description
+ << ", Dedicated VRAM: " << (desc.DedicatedVideoMemory / 1024 / 1024) << " MB"
+ << ", Vendor: 0x" << std::hex << desc.VendorId << std::dec
+ << ", Flags: " << desc.Flags << LL_ENDL;
+ }
+ // Skip Microsoft Basic Render Driver, it's a placeholder for missing drivers
+ else if (description.find("Microsoft Basic Render Driver") != std::string::npos)
+ {
+ // User is likely missing drivers, so log a warning.
+ // Don't consider this adapter as a valid selection.
+ LL_WARNS("Window") << "Adapter " << adapterIndex << ": " << description
+ << ", Dedicated VRAM: " << (desc.DedicatedVideoMemory / 1024 / 1024) << " MB"
+ << ", Vendor: 0x" << std::hex << desc.VendorId << std::dec
+ << ", Flags: " << desc.Flags << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS("Window") << "Adapter " << adapterIndex << ": " << description
+ << ", Dedicated VRAM: " << (desc.DedicatedVideoMemory / 1024 / 1024) << " MB"
+ << ", Vendor: 0x" << std::hex << desc.VendorId << std::dec
+ << ", Flags: " << desc.Flags << LL_ENDL;
+
+ adapter_count++;
+ // Select adapter with most dedicated video memory (typically the discrete GPU)
+ if (desc.DedicatedVideoMemory > maxDedicatedMemory)
+ {
+ if (pSelectedAdapter)
+ {
+ pSelectedAdapter->Release();
+ }
+ pSelectedAdapter = pAdapter;
+ pSelectedAdapter->AddRef();
+ maxDedicatedMemory = desc.DedicatedVideoMemory;
+ gExpectedAdapterLUID = desc.AdapterLuid;
+ selected_descr = description;
+ }
+ }
+
+ pAdapter->Release();
+ adapterIndex++;
+ }
+ pFactory->Release();
+
+ if (adapter_count < 2)
+ {
+ // Only one adapter, no need to request high-performance GPU
+ if (pSelectedAdapter)
+ {
+ pSelectedAdapter->Release();
+ }
+ gExpectedAdapterLUID = { 0, 0 };
+ FreeLibrary(gD3D11Library);
+ gD3D11Library = nullptr;
+ return;
+ }
+
+ LL_INFOS("Window") << "Selected as preferred adapter (highest VRAM): " << selected_descr << LL_ENDL;
+ }
+
+ // Create a temporary device to ensure high-performance GPU is selected
+ // This initialization can help "wake up" the discrete GPU
+ D3D_FEATURE_LEVEL featureLevel;
+ D3D_FEATURE_LEVEL requestedLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1 };
+
+ bool adapterSelected = (pSelectedAdapter != nullptr);
+ if (adapterSelected)
+ {
+ hr = pD3D11CreateDevice(
+ pSelectedAdapter,
+ D3D_DRIVER_TYPE_UNKNOWN,
+ nullptr,
+ 0,
+ requestedLevels,
+ _countof(requestedLevels),
+ D3D11_SDK_VERSION,
+ &gD3D11Device,
+ &featureLevel,
+ &gD3D11Context
+ );
+ pSelectedAdapter->Release();
+
+ if (!SUCCEEDED(hr))
+ {
+ LL_WARNS("Window") << "D3D11 failed to use preffered adapter " << selected_descr << LL_ENDL;
+ gExpectedAdapterLUID = { 0, 0 };
+ adapterSelected = false;
+ }
+ }
+
+ if (!adapterSelected)
+ {
+ // Either failed to select or didn't find an adapter.
+ hr = pD3D11CreateDevice(
+ nullptr,
+ D3D_DRIVER_TYPE_HARDWARE,
+ nullptr,
+ 0,
+ requestedLevels,
+ _countof(requestedLevels),
+ D3D11_SDK_VERSION,
+ &gD3D11Device,
+ &featureLevel,
+ &gD3D11Context
+ );
+ if (!SUCCEEDED(hr))
+ {
+ LL_WARNS("Window") << "D3D11 failed to use hardware adapter" << LL_ENDL;
+ FreeLibrary(gD3D11Library);
+ gD3D11Library = nullptr;
+ // These shouldn't be set, but make sure they are null.
+ gD3D11Device = nullptr;
+ gD3D11Context = nullptr;
+ }
+ }
+ }
+ else
+ {
+ LL_WARNS("Window") << "Failed to get D3D11CreateDevice function from d3d11.dll. High-performance GPU request failed." << LL_ENDL;
+ FreeLibrary(gD3D11Library);
+ gD3D11Library = nullptr;
+ }
+ }
+}
+
+bool LLWindowWin32::detectGPUChange() const
+{
+ if (!gD3D11Device)
+ {
+ // Can't detect without D3D11 device
+ return false;
+ }
+
+ if (gExpectedAdapterLUID.LowPart == 0 && gExpectedAdapterLUID.HighPart == 0)
+ {
+ // No specific adapter was selected, can't detect changes.
+ return false;
+ }
+
+ IDXGIDevice* pDXGIDevice = nullptr;
+ HRESULT hr = gD3D11Device->QueryInterface(__uuidof(IDXGIDevice), (void**)&pDXGIDevice);
+
+ if (SUCCEEDED(hr) && pDXGIDevice)
+ {
+ IDXGIAdapter* pCurrentAdapter = nullptr;
+ hr = pDXGIDevice->GetAdapter(&pCurrentAdapter);
+
+ if (SUCCEEDED(hr) && pCurrentAdapter)
+ {
+ DXGI_ADAPTER_DESC desc;
+ pCurrentAdapter->GetDesc(&desc);
+
+ std::wstring description_w(desc.Description);
+
+ bool changed = false;
+
+ // Check if LUID has changed
+ if (desc.AdapterLuid.LowPart != gExpectedAdapterLUID.LowPart ||
+ desc.AdapterLuid.HighPart != gExpectedAdapterLUID.HighPart)
+ {
+ changed = true;
+ std::string current_gpu_name = ll_convert_wide_to_string(description_w);
+ LL_WARNS("Window") << "GPU change detected! Current adapter: " << current_gpu_name << LL_ENDL;
+ }
+
+ pCurrentAdapter->Release();
+ pDXGIDevice->Release();
+
+ return changed;
+ }
+
+ if (pDXGIDevice)
+ {
+ pDXGIDevice->Release();
+ }
+ }
+
+ return false;
+}
+
+void LLWindowWin32::clearHighPerformanceGPURequest() const
+{
+ detectGPUChange();
+ gExpectedAdapterLUID = { 0, 0 };
+ if (gD3D11Context)
+ {
+ gD3D11Context->Release();
+ gD3D11Context = nullptr;
+ }
+ if (gD3D11Device)
+ {
+ gD3D11Device->Release();
+ gD3D11Device = nullptr;
+ }
+ if (gD3D11Library)
+ {
+ FreeLibrary(gD3D11Library);
+ gD3D11Library = nullptr;
+ }
+}
+
void* LLWindowWin32::getDirectInput8()
{
return &gDirectInput8;
@@ -4503,6 +5247,17 @@ bool LLWindowWin32::getInputDevices(U32 device_type_filter,
return false;
}
+void LLWindowWin32::initWatchdog()
+{
+ mWindowThread->initTimeout();
+
+ // Watchdog is effectively a 'login complete event', as the
+ // 'unstable' part is done and from now on we are tracking
+ // performance.
+ // No need to hold D3D11 context/device any more.
+ clearHighPerformanceGPURequest();
+}
+
F32 LLWindowWin32::getSystemUISize()
{
F32 scale_value = 1.f;
@@ -4565,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();
@@ -4576,28 +5343,27 @@ 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()
- : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, true /*should be false, temporary workaround for SL-18721*/)
+ : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, false)
{
LL::ThreadPool::start();
-}
-void LLWindowWin32::LLWindowWin32Thread::close()
-{
- if (!mQueue->isClosed())
+ // Set thread name for the window thread
+ // This will make it distinguishable in Visual Studio debugger
+ post([this]()
{
- LL_WARNS() << "Closing window thread without using destroy_window_handler" << LL_ENDL;
- LL::ThreadPool::close();
-
- // Workaround for SL-18721 in case window closes too early and abruptly
- LLSplashScreen::show();
- LLSplashScreen::update("..."); // will be updated later
- }
+ SetThreadDescription(GetCurrentThread(), L"LLWindowWin32 Thread");
+ });
}
-
/**
* LogChange is to log changes in status while trying to avoid spamming the
* log with repeated messages, especially in a tight loop. It refuses to log
@@ -4654,6 +5420,8 @@ void LLWindowWin32::LLWindowWin32Thread::checkDXMem()
return;
}
+ pauseTimeout();
+
IDXGIFactory4* p_factory = nullptr;
HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&p_factory);
@@ -4757,6 +5525,8 @@ void LLWindowWin32::LLWindowWin32Thread::checkDXMem()
}
mGotGLBuffer = true;
+
+ resumeTimeout("checkDXMem");
}
void LLWindowWin32::LLWindowWin32Thread::run()
@@ -4772,6 +5542,9 @@ void LLWindowWin32::LLWindowWin32Thread::run()
timeBeginPeriod(llclamp((U32) 1, tc.wPeriodMin, tc.wPeriodMax));
}
+ // Normally won't exist yet, but in case of re-init, make sure it's cleaned up
+ resumeTimeout("Window:WindowThread");
+
while (! getQueue().done())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
@@ -4785,18 +5558,21 @@ void LLWindowWin32::LLWindowWin32Thread::run()
BOOL status;
if (mhDCThrd == 0)
{
+ pingTimeout("Window:PeekMessage");
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - PeekMessage");
logger.onChange("PeekMessage(", std::hex, mWindowHandleThrd, ")");
status = PeekMessage(&msg, mWindowHandleThrd, 0, 0, PM_REMOVE);
}
else
{
+ pingTimeout("Window:GetMessage");
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - GetMessage");
logger.always("GetMessage(", std::hex, mWindowHandleThrd, ")");
status = GetMessage(&msg, NULL, 0, 0);
}
if (status > 0)
{
+ pingTimeout("Window:TranslateMessage");
logger.always("got MSG (", std::hex, msg.hwnd, ", ", msg.message,
", ", msg.wParam, ")");
TranslateMessage(&msg);
@@ -4808,6 +5584,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Function Queue");
+ pingTimeout("Window:Queue");
logger.onChange("runPending()");
//process any pending functions
getQueue().runPending();
@@ -4821,108 +5598,103 @@ void LLWindowWin32::LLWindowWin32Thread::run()
}
#endif
}
+
+ pauseTimeout();
+ destroyWindow();
+
+ if (mDeleteOnExit)
+ {
+ delete this;
+ }
+}
+
+void LLWindowWin32::LLWindowWin32Thread::destroyWindow()
+{
+ if (mWindowHandleThrd != NULL && IsWindow(mWindowHandleThrd))
+ {
+ if (mhDCThrd)
+ {
+ if (!ReleaseDC(mWindowHandleThrd, mhDCThrd))
+ {
+ LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
+ }
+ mhDCThrd = NULL;
+ }
+
+ // This causes WM_DESTROY to be sent *immediately*
+ if (!destroy_window_handler(mWindowHandleThrd))
+ {
+ LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL;
+ }
+ }
+ else
+ {
+ // Something killed the window while we were busy destroying gl or handle somehow got broken
+ LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
+ }
+ mWindowHandleThrd = NULL;
+ mhDCThrd = NULL;
}
-void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
+bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
{
if (mQueue->isClosed())
{
- LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL;
- return;
+ LL_WARNS("Window") << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL;
+ return false;
}
- // Make sure we don't leave a blank toolbar button.
- // Also hiding window now prevents user from suspending it
- // via some action (like dragging it around)
- ShowWindow(mWindowHandleThrd, SW_HIDE);
+ // Stop checking budget
+ mGLReady = false;
- // Schedule destruction
+ // Capture current handle before we lose it
HWND old_handle = mWindowHandleThrd;
- post([this]()
- {
- if (IsWindow(mWindowHandleThrd))
- {
- if (mhDCThrd)
- {
- if (!ReleaseDC(mWindowHandleThrd, mhDCThrd))
- {
- LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
- }
- mhDCThrd = NULL;
- }
- // This causes WM_DESTROY to be sent *immediately*
- if (!destroy_window_handler(mWindowHandleThrd))
- {
- LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL;
- }
- }
- else
- {
- // Something killed the window while we were busy destroying gl or handle somehow got broken
- LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
- }
- mWindowHandleThrd = NULL;
- mhDCThrd = NULL;
- mGLReady = false;
- });
-
- LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL;
- mQueue->close();
-
- // Post a nonsense user message to wake up the thread in
- // case it is waiting for a getMessage()
+ // Clear the user data to prevent callbacks from finding us
if (old_handle)
{
- WPARAM wparam{ 0xB0B0 };
- LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle
- << ", " << WM_DUMMY_
- << ", " << wparam << ")" << std::dec << LL_ENDL;
- PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337);
+ SetWindowLongPtr(old_handle, GWLP_USERDATA, NULL);
}
- // There are cases where window will refuse to close,
- // can't wait forever on join, check state instead
- LLTimer timeout;
- timeout.setTimerExpirySec(2.0);
- while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd)
- {
- ms_sleep(100);
- }
+ // Signal thread to clean up when done
+ mDeleteOnExit = true;
- if (getQueue().done() || mWindowHandleThrd == NULL)
+ LL_INFOS("Window") << "Detaching window's thread" << LL_ENDL;
+ // Cleanly detach threads instead of joining them to avoid blocking the main thread
+ // This is acceptable since the thread will self-delete with mDeleteOnExit
+ // Doing it before close() to make sure thread doesn't die before or mid detach.
+ for (auto& pair : mThreads)
{
- // Window is closed, started closing or is cleaning up
- // now wait for our single thread to die.
- if (mWindowHandleThrd)
- {
- LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
+ try {
+ // Only detach if the thread is joinable
+ if (pair.second.joinable())
+ {
+ pair.second.detach();
+ }
}
- for (auto& pair : mThreads)
- {
- pair.second.join();
+ catch (const std::system_error& e) {
+ LL_WARNS("Window") << "Exception detaching thread: " << e.what() << LL_ENDL;
}
}
- else
+
+ // Close the queue.
+ LL_INFOS("Window") << "Closing window's pool queue" << LL_ENDL;
+ mQueue->close();
+
+ // Wake up the thread if it's stuck in GetMessage()
+ if (old_handle)
{
- // Something suspended window thread, can't afford to wait forever
- // so kill thread instead
- // Ex: This can happen if user starts dragging window arround (if it
- // was visible) or a modal notification pops up
- LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL;
+ WPARAM wparam{ 0xB0B0 };
+ LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle
+ << ", " << WM_DUMMY_
+ << ", " << wparam << ")" << std::dec << LL_ENDL;
- for (auto& pair : mThreads)
- {
- // very unsafe
- TerminateThread(pair.second.native_handle(), 0);
- pair.second.detach();
- }
+ // Use PostMessage to signal thread to wake up
+ PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337);
}
- LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL;
+
+ LL_INFOS("Window") << "Thread pool shutdown complete" << LL_ENDL;
+ return true;
}
void LLWindowWin32::post(const std::function<void()>& func)
@@ -4969,3 +5741,69 @@ void LLWindowWin32::updateWindowRect()
});
}
}
+
+bool LLWindowWin32::isSystemAppDarkMode()
+{
+ HKEY hKey;
+ DWORD dwValue = 1; // Default to light theme
+ DWORD dwSize = sizeof(DWORD);
+
+ // Check registry for system theme preference
+ LSTATUS ret_code =
+ RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey);
+ if (ERROR_SUCCESS == ret_code)
+ {
+ if (RegQueryValueExW(hKey, L"AppsUseLightTheme", NULL, NULL, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS)
+ {
+ // If AppsUseLightTheme is not found, check SystemUsesLightTheme
+ dwSize = sizeof(DWORD);
+ RegQueryValueExW(hKey, L"SystemUsesLightTheme", NULL, NULL, (LPBYTE)&dwValue, &dwSize);
+ }
+ RegCloseKey(hKey);
+ }
+
+ // Return true if dark mode
+ return dwValue == 0;
+}
+
+void LLWindowWin32::updateWindowTheme()
+{
+ bool use_dark_mode = isSystemAppDarkMode();
+ if (use_dark_mode == mCurrentDarkMode)
+ {
+ return;
+ }
+ mCurrentDarkMode = use_dark_mode;
+
+ HMODULE hUxTheme = LoadLibraryExW(L"uxtheme.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+ if (hUxTheme)
+ {
+ auto SetPreferredAppMode = (fnSetPreferredAppMode)GetProcAddress(hUxTheme, "SetPreferredAppMode");
+ if (SetPreferredAppMode)
+ {
+ SetPreferredAppMode(use_dark_mode ? ALLOW_DARK : FORCE_LIGHT);
+ }
+ FreeLibrary(hUxTheme);
+ }
+ BOOL dark_mode(use_dark_mode);
+ DwmSetWindowAttribute(mWindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark_mode, sizeof(dark_mode));
+
+ LL_INFOS("Window") << "Viewer window theme is set to " << (use_dark_mode ? "dark" : "light") << " mode" << LL_ENDL;
+}
+
+void LLWindowWin32::setCustomIcon()
+{
+ if (mWindowHandle)
+ {
+ HICON hDefaultIcon = LoadIcon(mhInstance, mIconResource);
+ HICON hSmallIcon = LoadIcon(mhInstance, mIconSmallResource);
+ mWindowThread->post([=]()
+ {
+ SendMessage(mWindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hDefaultIcon);
+ SendMessage(mWindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon);
+
+ SetClassLongPtr(mWindowHandle, GCLP_HICON, (LONG_PTR)hDefaultIcon);
+ SetClassLongPtr(mWindowHandle, GCLP_HICONSM, (LONG_PTR)hSmallIcon);
+ });
+ }
+}
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 36e89e4586..9ccd0a3ee2 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -40,102 +40,116 @@
// 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
{
public:
- /*virtual*/ void show();
- /*virtual*/ void hide();
- /*virtual*/ void close();
- /*virtual*/ bool getVisible();
- /*virtual*/ bool getMinimized();
- /*virtual*/ bool getMaximized();
- /*virtual*/ bool maximize();
- /*virtual*/ void minimize();
- /*virtual*/ void restore();
- /*virtual*/ bool getFullscreen();
- /*virtual*/ bool getPosition(LLCoordScreen *position);
- /*virtual*/ bool getSize(LLCoordScreen *size);
- /*virtual*/ bool getSize(LLCoordWindow *size);
- /*virtual*/ bool setPosition(LLCoordScreen position);
- /*virtual*/ bool setSizeImpl(LLCoordScreen size);
- /*virtual*/ bool setSizeImpl(LLCoordWindow size);
- /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL);
- /*virtual*/ void setTitle(const std::string title);
+ void show() override;
+ void hide() override;
+ void close() override;
+ bool getVisible() override;
+ bool getMinimized() override;
+ bool getMaximized() override;
+ bool maximize() override;
+ void minimize() override;
+ void restore() override;
+ bool getFullscreen();
+ bool getPosition(LLCoordScreen *position) override;
+
+ // Outer window frame size in pixels (includes title bar and borders).
+ // Note OS Specific behavior: On macOS excludes title bar.
+ bool getSize(LLCoordScreen *size) override;
+
+ bool getSize(LLCoordWindow *size) override;
+ bool setPosition(LLCoordScreen position) override;
+ bool setSizeImpl(LLCoordScreen size) override;
+ bool setSizeImpl(LLCoordWindow size) override;
+ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) override;
+ void setTitle(const std::string title) override;
void* createSharedContext() override;
void makeContextCurrent(void* context) override;
void destroySharedContext(void* context) override;
- /*virtual*/ void toggleVSync(bool enable_vsync);
- /*virtual*/ bool setCursorPosition(LLCoordWindow position);
- /*virtual*/ bool getCursorPosition(LLCoordWindow *position);
- /*virtual*/ bool getCursorDelta(LLCoordCommon* delta);
- /*virtual*/ void showCursor();
- /*virtual*/ void hideCursor();
- /*virtual*/ void showCursorFromMouseMove();
- /*virtual*/ void hideCursorUntilMouseMove();
- /*virtual*/ bool isCursorHidden();
- /*virtual*/ void updateCursor();
- /*virtual*/ ECursorType getCursor() const;
- /*virtual*/ void captureMouse();
- /*virtual*/ void releaseMouse();
- /*virtual*/ void setMouseClipping( bool b );
- /*virtual*/ bool isClipboardTextAvailable();
- /*virtual*/ bool pasteTextFromClipboard(LLWString &dst);
- /*virtual*/ bool copyTextToClipboard(const LLWString &src);
- /*virtual*/ void flashIcon(F32 seconds);
- /*virtual*/ F32 getGamma();
- /*virtual*/ bool setGamma(const F32 gamma); // Set the gamma
- /*virtual*/ void setFSAASamples(const U32 fsaa_samples);
- /*virtual*/ U32 getFSAASamples();
- /*virtual*/ bool restoreGamma(); // Restore original gamma table (before updating gamma)
- /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; }
- /*virtual*/ void gatherInput();
- /*virtual*/ void delayInputProcessing();
- /*virtual*/ void swapBuffers();
- /*virtual*/ void restoreGLContext() {};
+ void toggleVSync(bool enable_vsync) override;
+ bool setCursorPosition(LLCoordWindow position) override;
+ bool getCursorPosition(LLCoordWindow *position) override;
+ bool getCursorDelta(LLCoordCommon* delta) override;
+ bool isWrapMouse() const override { return !mAbsoluteCursorPosition; };
+ void showCursor() override;
+ void hideCursor() override;
+ void showCursorFromMouseMove() override;
+ void hideCursorUntilMouseMove() override;
+ bool isCursorHidden() override;
+ void updateCursor() override;
+ ECursorType getCursor() const override;
+ void captureMouse() override;
+ void releaseMouse() override;
+ void setMouseClipping( bool b ) override;
+ bool isClipboardTextAvailable() override;
+ bool pasteTextFromClipboard(LLWString &dst) override;
+ bool copyTextToClipboard(const LLWString &src) override;
+ void flashIcon(F32 seconds) override;
+ F32 getGamma() override;
+ bool setGamma(const F32 gamma) override; // Set the gamma
+ void setFSAASamples(const U32 fsaa_samples) override;
+ U32 getFSAASamples() override;
+ bool restoreGamma() override; // Restore original gamma table (before updating gamma)
+ ESwapMethod getSwapMethod() override { return mSwapMethod; }
+ void gatherInput() override;
+ void delayInputProcessing() override;
+ void swapBuffers() override;
// handy coordinate space conversion routines
- /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to);
- /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to);
- /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to);
- /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to);
- /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to);
- /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to);
+ bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override;
+ bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override;
+ bool convertCoords(LLCoordWindow from, LLCoordGL *to) override;
+ bool convertCoords(LLCoordGL from, LLCoordWindow *to) override;
+ bool convertCoords(LLCoordScreen from, LLCoordGL *to) override;
+ bool convertCoords(LLCoordGL from, LLCoordScreen *to) override;
- /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions);
- /*virtual*/ F32 getNativeAspectRatio();
- /*virtual*/ F32 getPixelAspectRatio();
- /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; }
+ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override;
+ F32 getNativeAspectRatio() override;
+ F32 getPixelAspectRatio() override;
+ void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; }
- /*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b );
+ bool dialogColorPicker(F32 *r, F32 *g, F32 *b ) override;
- /*virtual*/ void *getPlatformWindow();
- /*virtual*/ void bringToFront();
- /*virtual*/ void focusClient();
+ void *getPlatformWindow() override;
+ void bringToFront() override;
+ void focusClient() override;
- /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, bool b);
- /*virtual*/ void setLanguageTextInput( const LLCoordGL & pos );
- /*virtual*/ void updateLanguageTextInputArea();
- /*virtual*/ void interruptLanguageTextInput();
- /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async);
+ void allowLanguageTextInput(LLPreeditor *preeditor, bool b) override;
+ void setLanguageTextInput( const LLCoordGL & pos ) override;
+ void updateLanguageTextInputArea() override;
+ void interruptLanguageTextInput() override;
+ void spawnWebBrowser(const std::string& escaped_url, bool async) override;
- /*virtual*/ F32 getSystemUISize();
+ F32 getSystemUISize() override;
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();
- /*virtual*/ void* getDirectInput8();
- /*virtual*/ bool getInputDevices(U32 device_type_filter,
+ void* getDirectInput8() override;
+ bool getInputDevices(U32 device_type_filter,
std::function<bool(std::string&, LLSD&, void*)> osx_callback,
void* win_callback,
- void* userdata);
+ void* userdata) override;
U32 getRawWParam() { return mRawWParam; }
+ void initWatchdog() override;
+
protected:
LLWindowWin32(LLWindowCallbacks* callbacks,
const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
@@ -146,11 +160,13 @@ protected:
void initCursors();
HCURSOR loadColorCursor(LPCTSTR name);
bool isValid();
+ void setThreadPriorityHigh();
+ void setThreadPriorityNormal();
void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size);
virtual LLSD getNativeKeyData();
// Changes display resolution. Returns true if successful
- bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh);
+ bool setDisplayResolution(S32 width, S32 height, S32 refresh);
// Go back to last fullscreen display resolution.
bool setFullscreenResolution();
@@ -168,6 +184,17 @@ protected:
void handleCompositionMessage(U32 indexes);
bool handleImeRequests(WPARAM request, LPARAM param, LRESULT *result);
+ // Additional function to request and hold a high-performance GPU on Windows 10+
+ //
+ // Laptops can dynamically switch between integrated and discrete GPUs.
+ // The Viewer has gpu-specific optimizations, and this switching can cause problems and crashes.
+ // The login screen requires low performance, which can lead to the OS deciding to switch to the integrated GPU.
+ // To avoid this, we request and hold a high-performance GPU using A D3D11 context until login.
+ // For diagnostics, we also log GPU changes.
+ void requestHighPerformanceGPU() const;
+ bool detectGPUChange() const;
+ void clearHighPerformanceGPURequest() const;
+
protected:
//
// Platform specific methods
@@ -195,6 +222,7 @@ protected:
HCURSOR mCursor[ UI_CURSOR_COUNT ]; // Array of all mouse cursors
LLCoordWindow mCursorPosition; // mouse cursor position, should only be mutated on main thread
+ bool mAbsoluteCursorPosition; // true if last position was received in absolute coordinates.
LLMutex mRawMouseMutex;
RAWINPUTDEVICE mRawMouse;
LLCoordWindow mLastCursorPosition; // mouse cursor position from previous frame
@@ -214,7 +242,9 @@ protected:
bool mCustomGammaSet;
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
@@ -241,11 +271,18 @@ protected:
bool mMouseVanish;
+ static HMODULE sGLDLLHandle;
+
// Cached values of GetWindowRect and GetClientRect to be used by app thread
void updateWindowRect();
RECT mRect;
RECT mClientRect;
+ void updateWindowTheme();
+ bool isSystemAppDarkMode();
+ void setCustomIcon();
+ bool mCurrentDarkMode { false };
+
struct LLWindowWin32Thread;
LLWindowWin32Thread* mWindowThread = nullptr;
LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
@@ -281,6 +318,7 @@ private:
extern LLW32MsgCallback gAsyncMsgCallback;
extern LPWSTR gIconResource;
+extern LPWSTR gIconSmallResource;
S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type);