From ea650ac073aeb03ab99b88c41f51ce636ce37982 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew.l.meadows@gmail.com>
Date: Thu, 3 Oct 2024 12:08:26 -0700
Subject: fix GameControl save settings, fix linux build

---
 indra/cmake/LLWindow.cmake            |  5 ++++
 indra/llcommon/llthreadsafequeue.h    |  5 +++-
 indra/llwindow/llgamecontrol.cpp      | 14 ++++------
 indra/llwindow/llgamecontrol.h        |  6 ++---
 indra/llwindow/llkeyboard.h           |  2 +-
 indra/newview/llagent.cpp             |  1 +
 indra/newview/llfloaterpreference.cpp |  5 ++--
 indra/newview/llfloaterpreference.h   | 48 +++++++++++++++++------------------
 indra/newview/llflycam.cpp            |  4 +--
 9 files changed, 47 insertions(+), 43 deletions(-)

diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake
index b2c1792df1..a5791f1bef 100644
--- a/indra/cmake/LLWindow.cmake
+++ b/indra/cmake/LLWindow.cmake
@@ -6,3 +6,8 @@ include(Prebuilt)
 include(SDL2)
 
 include_guard()
+
+if (LINUX)
+  # linux uses SDL2 for window and keyboard
+  target_compile_definitions( ll::SDL2 INTERFACE LL_USE_SDL_KEYBOARD=1 )
+endif (LINUX)
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 034e3f7897..7a5eb5b33d 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -452,7 +452,10 @@ ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
         // so we can finish draining the queue.
         pop_result popped = pop_(lock1, value);
         if (popped == POPPED)
-            return std::move(value);
+            // don't use std::move when returning local value because
+            // it prevents the compiler from optimizing with copy elision
+            //return std::move(value);
+            return value;
 
         // Once the queue is DONE, there will never be any more coming.
         if (popped == DONE)
diff --git a/indra/llwindow/llgamecontrol.cpp b/indra/llwindow/llgamecontrol.cpp
index 01c6f91d25..9d3c854ca2 100644
--- a/indra/llwindow/llgamecontrol.cpp
+++ b/indra/llwindow/llgamecontrol.cpp
@@ -41,11 +41,6 @@
 
 namespace std
 {
-    string to_string(const char* text)
-    {
-        return text ? string(text) : LLStringUtil::null;
-    }
-
     string to_string(const SDL_JoystickGUID& guid)
     {
         char buffer[33] = { 0 };
@@ -149,7 +144,7 @@ namespace std
         SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
         ss << ",guid:'" << guid << "'";
         ss << ",type:'" << SDL_JoystickGetType(joystick) << "'";
-        ss << ",name:'" << std::to_string(SDL_JoystickName(joystick)) << "'";
+        ss << ",name:'" << ll_safe_string(SDL_JoystickName(joystick)) << "'";
         ss << ",vendor:" << SDL_JoystickGetVendor(joystick);
         ss << ",product:" << SDL_JoystickGetProduct(joystick);
         if (U16 version = SDL_JoystickGetProductVersion(joystick))
@@ -179,7 +174,7 @@ namespace std
         stringstream ss;
 
         ss << "{type:'" << SDL_GameControllerGetType(controller) << "'";
-        ss << ",name:'" << std::to_string(SDL_GameControllerName(controller)) << "'";
+        ss << ",name:'" << ll_safe_string(SDL_GameControllerName(controller)) << "'";
         ss << ",vendor:" << SDL_GameControllerGetVendor(controller);
         ss << ",product:" << SDL_GameControllerGetProduct(controller);
         if (U16 version = SDL_GameControllerGetProductVersion(controller))
@@ -1411,7 +1406,7 @@ void onJoystickDeviceAdded(const SDL_Event& event)
 {
     SDL_JoystickGUID guid(SDL_JoystickGetDeviceGUID(event.cdevice.which));
     SDL_JoystickType type(SDL_JoystickGetDeviceType(event.cdevice.which));
-    std::string name(std::to_string(SDL_JoystickNameForIndex(event.cdevice.which)));
+    std::string name(ll_safe_string(SDL_JoystickNameForIndex(event.cdevice.which)));
 
     LL_INFOS("SDL2") << "joystick {id:" << event.cdevice.which
         << ",guid:'" << guid << "'"
@@ -1438,7 +1433,7 @@ void onControllerDeviceAdded(const SDL_Event& event)
 {
     std::string guid(std::to_string(SDL_JoystickGetDeviceGUID(event.cdevice.which)));
     SDL_GameControllerType type(SDL_GameControllerTypeForIndex(event.cdevice.which));
-    std::string name(std::to_string(SDL_GameControllerNameForIndex(event.cdevice.which)));
+    std::string name(ll_safe_string(SDL_GameControllerNameForIndex(event.cdevice.which)));
 
     LL_INFOS("SDL2") << "controller {id:" << event.cdevice.which
         << ",guid:'" << guid << "'"
@@ -1514,6 +1509,7 @@ bool LLGameControl::isInitialized()
 }
 
 // static
+// TODO: find a cleaner way to provide callbacks to LLGameControl
 void LLGameControl::init(const std::string& gamecontrollerdb_path,
     std::function<bool(const std::string&)> loadBoolean,
     std::function<void(const std::string&, bool)> saveBoolean,
diff --git a/indra/llwindow/llgamecontrol.h b/indra/llwindow/llgamecontrol.h
index 5472a8ce6d..a4b47cc47f 100644
--- a/indra/llwindow/llgamecontrol.h
+++ b/indra/llwindow/llgamecontrol.h
@@ -40,10 +40,10 @@
 //
 //                 leftpaddle                          rightpaddle
 //                 _______                               _______
-//                /   4+  '-.                         .-'  5+   \
+//                /   4+  '-.                         .-'  5+   \.
 // leftshoulder _(9)_________'-.____           ____.-'_________(10) rightshoulder
-//             /  _________         \_________/                   \
-//            /  /    1-   \                               (3)     \
+//             /  _________         \_________/                   \.
+//            /  /    1-   \                               (3)     \.
 //            | |           |     (4)   (5)   (6)           Y      |
 //            | |0-  (7)  0+|               _________  (2)X   B(1) |
 //            | |           |              /    3-   \      A      |
diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h
index da406b28e8..c092f55685 100644
--- a/indra/llwindow/llkeyboard.h
+++ b/indra/llwindow/llkeyboard.h
@@ -55,7 +55,7 @@ class LLWindowCallbacks;
 class LLKeyboard
 {
 public:
-#ifdef LL_LINUX
+#ifdef LL_USE_SDL_KEYBOARD
     // linux relies on SDL2 which uses U32 for its native key type
     typedef U32 NATIVE_KEY_TYPE;
 #else
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index b7257a6c50..ca35608175 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -4989,6 +4989,7 @@ static S32 g_deltaFrame { 0 };
 
 void LLAgent::applyExternalActionFlags(U32 outer_flags)
 {
+    llassert(LLCoros::on_main_thread_main_coro());
     assert(LLGameControl::isEnabled() && LLGameControl::willControlAvatar());
     mExternalActionFlags = outer_flags;
 
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index ec725a8ace..0c96c93d31 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -647,7 +647,7 @@ void LLFloaterPreference::cancel(const std::vector<std::string> settings_to_skip
     {
         if (LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view))
         {
-            panel->cancel();
+            panel->cancel(settings_to_skip);
         }
     }
     // hide joystick pref floater
@@ -3223,8 +3223,6 @@ void LLPanelPreferenceGameControl::saveSettings()
     };
 
     // Use string formatting functions provided by class LLGameControl:
-    // stringifyAnalogMappings(), stringifyBinaryMappings(), stringifyFlycamMappings()
-
     if (LLControlVariable* analogMappings = gSavedSettings.getControl("AnalogChannelMappings"))
     {
         analogMappings->set(LLGameControl::stringifyAnalogMappings(getChannel));
@@ -3496,6 +3494,7 @@ void LLPanelPreferenceGameControl::onCommitNumericValue()
             deviceOptions.getAxisOptions()[row_index].mOffset = (S16)value;
         }
         setNumericLabel(row->getColumn(column_index), value);
+        LLGameControl::setDeviceOptions(mSelectedDeviceGUID, deviceOptions);
     }
 }
 
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 33d1cb0c87..e06e758e3a 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -447,38 +447,38 @@ private:
     void resetButtonMappingsToDefaults();
 
     // Above the tab container
-    LLCheckBoxCtrl* mCheckGameControlToServer; // send game_control data to server
-    LLCheckBoxCtrl* mCheckGameControlToAgent;  // use game_control data to move avatar
-    LLCheckBoxCtrl* mCheckAgentToGameControl;  // translate external avatar actions to game_control data
+    LLCheckBoxCtrl* mCheckGameControlToServer { nullptr }; // send game_control data to server
+    LLCheckBoxCtrl* mCheckGameControlToAgent { nullptr };  // use game_control data to move avatar
+    LLCheckBoxCtrl* mCheckAgentToGameControl { nullptr };  // translate external avatar actions to game_control data
 
     // 1st tab "Channel mappings"
-    LLPanel* mTabChannelMappings;
-    LLScrollListCtrl* mActionTable;
+    LLPanel* mTabChannelMappings { nullptr };
+    LLScrollListCtrl* mActionTable { nullptr };
 
     // 2nd tab "Device settings"
-    LLPanel* mTabDeviceSettings;
-    LLTextBox* mNoDeviceMessage;
-    LLTextBox* mDevicePrompt;
-    LLTextBox* mSingleDevice;
-    LLComboBox* mDeviceList;
-    LLCheckBoxCtrl* mCheckShowAllDevices;
-    LLPanel* mPanelDeviceSettings;
-    LLPanel* mTabAxisOptions;
-    LLScrollListCtrl* mAxisOptions;
-    LLPanel* mTabAxisMappings;
-    LLScrollListCtrl* mAxisMappings;
-    LLPanel* mTabButtonMappings;
-    LLScrollListCtrl* mButtonMappings;
-
-    LLButton* mResetToDefaults;
+    LLPanel* mTabDeviceSettings { nullptr };
+    LLTextBox* mNoDeviceMessage { nullptr };
+    LLTextBox* mDevicePrompt { nullptr };
+    LLTextBox* mSingleDevice { nullptr };
+    LLComboBox* mDeviceList { nullptr };
+    LLCheckBoxCtrl* mCheckShowAllDevices { nullptr };
+    LLPanel* mPanelDeviceSettings { nullptr };
+    LLPanel* mTabAxisOptions { nullptr };
+    LLScrollListCtrl* mAxisOptions { nullptr };
+    LLPanel* mTabAxisMappings { nullptr };
+    LLScrollListCtrl* mAxisMappings { nullptr };
+    LLPanel* mTabButtonMappings { nullptr };
+    LLScrollListCtrl* mButtonMappings { nullptr };
+
+    LLButton* mResetToDefaults { nullptr };
 
     // Numeric value editor
-    LLSpinCtrl* mNumericValueEditor;
+    LLSpinCtrl* mNumericValueEditor { nullptr };
 
     // Channel selectors
-    LLComboBox* mAnalogChannelSelector;
-    LLComboBox* mBinaryChannelSelector;
-    LLComboBox* mAxisSelector;
+    LLComboBox* mAnalogChannelSelector { nullptr };
+    LLComboBox* mBinaryChannelSelector { nullptr };
+    LLComboBox* mAxisSelector { nullptr };
 
     struct DeviceOptions
     {
diff --git a/indra/newview/llflycam.cpp b/indra/newview/llflycam.cpp
index 9bd854a3cc..eb5bfecf73 100644
--- a/indra/newview/llflycam.cpp
+++ b/indra/newview/llflycam.cpp
@@ -51,7 +51,7 @@ void LLFlycam::getTransform(LLVector3& position_out, LLQuaternion& rotation_out)
 // 'view' is expected to be in radians
 void LLFlycam::setView(F32 view)
 {
-    mView = std::min(std::max(view, MIN_FIELD_OF_VIEW), MAX_FIELD_OF_VIEW);
+    mView = std::clamp(view, MIN_FIELD_OF_VIEW, MAX_FIELD_OF_VIEW);
 }
 
 
@@ -126,7 +126,7 @@ void LLFlycam::integrate(F32 delta_time)
     {
         // Note: we subtract the delta because "positive" zoom (e.g. "zoom in")
         // produces smaller view angle
-        mView = std::min(std::max(mView - delta_time * mZoomRate, MIN_FIELD_OF_VIEW), MAX_FIELD_OF_VIEW);
+        mView = std::clamp(mView - delta_time * mZoomRate, MIN_FIELD_OF_VIEW, MAX_FIELD_OF_VIEW);
     }
 
     if (needs_renormalization)
-- 
cgit v1.2.3