From a96071f9d3c0c0219226951c3263878b1638f26a Mon Sep 17 00:00:00 2001 From: Benau Date: Mon, 27 May 2019 12:17:08 +0800 Subject: [PATCH] Make android callback thread safe --- .../source/Irrlicht/CIrrDeviceAndroid.cpp | 10 ++++--- src/guiengine/engine.cpp | 30 +++++++++++++++++++ src/guiengine/engine.hpp | 5 ++++ src/guiengine/widgets/text_box_widget.cpp | 16 +++++++--- 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp b/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp index b22e4c7f6..e3e0029b9 100644 --- a/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp @@ -9,6 +9,7 @@ #ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ #include +#include #include #include "os.h" #include "CContextEGL.h" @@ -43,7 +44,7 @@ ANDROID_SAVE_CHARS_CALLBACK(ANDROID_PACKAGE_CALLBACK_NAME) // Call when android keyboard is opened or close, and save its height for // moving screen -int g_keyboard_height = 0; +std::atomic g_keyboard_height(0); #define MAKE_ANDROID_SAVE_KBD_HEIGHT_CALLBACK(x) JNIEXPORT void JNICALL Java_ ## x##_SuperTuxKartActivity_saveKeyboardHeight(JNIEnv* env, jobject this_obj, jint height) #define ANDROID_SAVE_KBD_HEIGHT_CALLBACK(PKG_NAME) MAKE_ANDROID_SAVE_KBD_HEIGHT_CALLBACK(PKG_NAME) @@ -51,7 +52,7 @@ int g_keyboard_height = 0; extern "C" ANDROID_SAVE_KBD_HEIGHT_CALLBACK(ANDROID_PACKAGE_CALLBACK_NAME) { - g_keyboard_height = (int)height; + g_keyboard_height.store((int)height); } namespace irr @@ -227,8 +228,9 @@ void CIrrDeviceAndroid::printConfig() u32 CIrrDeviceAndroid::getOnScreenKeyboardHeight() const { - if (g_keyboard_height > 0) - return g_keyboard_height; + int height = g_keyboard_height.load(); + if (height > 0) + return height; return 0; } diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index 7d93f1f1e..5a3285a7b 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -685,9 +685,11 @@ namespace GUIEngine #include "states_screens/race_gui_base.hpp" #include "utils/debug.hpp" +#include #include #include #include +#include using namespace irr::gui; using namespace irr::video; @@ -716,6 +718,10 @@ namespace GUIEngine int large_font_height; int small_font_height; int title_font_height; +#ifdef ANDROID + std::mutex m_gui_functions_mutex; + std::vector > m_gui_functions; +#endif } using namespace Private; @@ -1144,6 +1150,15 @@ namespace GUIEngine assert(g_skin->getReferenceCount() == 1); } // reloadSkin + // ----------------------------------------------------------------------- + void addGUIFunctionBeforeRendering(std::function func) + { +#ifdef ANDROID + std::lock_guard lock(m_gui_functions_mutex); + m_gui_functions.push_back(func); +#endif + } // addGUIFunctionBeforeRendering + // ----------------------------------------------------------------------- /** \brief called on every frame to trigger the rendering of the GUI. * \param elapsed_time Time since last rendering calls (in seconds). @@ -1158,6 +1173,21 @@ namespace GUIEngine // Not yet initialized, or already cleaned up if (g_skin == NULL) return; +#ifdef ANDROID + // Run all GUI functions first (if any) + std::unique_lock ul(m_gui_functions_mutex); + if (!m_gui_functions.empty()) + { + std::vector > functions; + std::swap(functions, m_gui_functions); + ul.unlock(); + for (auto& f : functions) + f(); + } + else + ul.unlock(); +#endif + // ---- menu drawing // draw background image and sections diff --git a/src/guiengine/engine.hpp b/src/guiengine/engine.hpp index c49dbf107..54e801c2c 100644 --- a/src/guiengine/engine.hpp +++ b/src/guiengine/engine.hpp @@ -34,6 +34,7 @@ namespace irr namespace video { class IVideoDriver; class ITexture; } } +#include #include #include "utils/constants.hpp" @@ -248,6 +249,10 @@ namespace GUIEngine */ void reloadSkin(); + /** + * \brief Add gui-related function before rendering GUI (from other thread) + */ + void addGUIFunctionBeforeRendering(std::function func); } #endif diff --git a/src/guiengine/widgets/text_box_widget.cpp b/src/guiengine/widgets/text_box_widget.cpp index 42dd57353..36e1fd6fc 100644 --- a/src/guiengine/widgets/text_box_widget.cpp +++ b/src/guiengine/widgets/text_box_widget.cpp @@ -246,8 +246,7 @@ EventPropagation TextBoxWidget::leftPressed (const int playerID) extern "C" ANDROID_EDITTEXT_CALLBACK(ANDROID_PACKAGE_CALLBACK_NAME) { - TextBoxWidget* tb = dynamic_cast(getFocusForPlayer(0)); - if (!tb || (int)widget_id != tb->getID() || text == NULL) + if (text == NULL) return; const char* utf8_text = env->GetStringUTFChars(text, NULL); @@ -262,8 +261,17 @@ ANDROID_EDITTEXT_CALLBACK(ANDROID_PACKAGE_CALLBACK_NAME) utf32line.push_back(0); core::stringw to_editbox(&utf32line[0]); - tb->getIrrlichtElement()->fromAndroidEditText( - to_editbox, start, end, composing_start, composing_end); env->ReleaseStringUTFChars(text, utf8_text); + + GUIEngine::addGUIFunctionBeforeRendering([widget_id, to_editbox, start, + end, composing_start, composing_end]() + { + TextBoxWidget* tb = + dynamic_cast(getFocusForPlayer(0)); + if (!tb || (int)widget_id != tb->getID()) + return; + tb->getIrrlichtElement()->fromAndroidEditText( + to_editbox, start, end, composing_start, composing_end); + }); } #endif