diff --git a/.efrocachemap b/.efrocachemap index 5f19889a..a48f4efd 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4060,26 +4060,26 @@ "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "d1b736e6185c6a77cabad635afe97d1c", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "93c74c5b4f9b7f528b0802aa7a23f677", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "36cba560a8171836dd7c9c6ff0ef9218", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "6e1d80e717d34d8594588d22a002e8f9", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "36a88b7c6b86f1acdd32ee4651496297", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "86399e9fed0bd310390595036e5a2567", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "f359b4e02f83e4aa04d7d0165b864de8", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "e244e4b6e699ccf65ccde669153290df", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "d31b4e34e21c25455380afa50ecf0fe7", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "3d1d0b4dd7df23c3c7e9958286211229", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "de5e043bf03efece2aa8a9ab3362749e", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "3bd9856b27825995919c9d0bbe6809cb", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "4e58688f6d42481fa175d6f0d43f8ab7", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "a05c25cdef7d3e81067c9645136a7b77", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "5501e98f9cea647b25a3702e26da5b31", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "8ef08bf21aeef91beecce31b79661a1a", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "51318d5ab8b474a01466eed83b8d9553", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "ea7ab32e245bb804cd09c9d111a7c10b", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "caabdfd17f1df3608a68cc96315ed4d5", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "8a9ed3e4672af09f5ea1b81d59dfb84f", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "9fe23e06319e4e256b9fa88814a14afa", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "4306acae21ce88235f9d1589086866e7", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "75e4f7d3a3df67dedd079ec3f4441094", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "bd5eda13f239b81886ac80596d6ade73", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "0805235a92dd91f96d43ea54575eecac", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "07589a61b11cbc5fca0bbc8b7fc1c955", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "f28629761060c8152168b6792b71adae", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "1cfd1a33474cdb31834994f626385ed0", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "d50879a92d9d344c376f6f196d78d1be", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "78cd0edf2698f197f2acd80ca364fae7", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "d656f47118ebc3af57c40423cb258bc8", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "75df540b27779342a7c696e1bdbe593f", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "76f0dfacaa9ea67e45e8ccf3bb3bc1c6", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "2acc754bed825a9265e0621dc09899e0", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "62c2b6190de8784ea8750ea50e6a2304", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "e57358fd9a948a8ce82a54cdd5c766fc", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "d36e3303e13049eae5e7ec19861d300e", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "46971a2ca1e3021e52ea5d0f4938d2ff", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "19ebd36613cf62c4bd50e70b93371368", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "49ef5905b6e9e1a9caaed3d1c1da4ea5", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "c22901e06e88a55cce0b4e08bbf41a4c", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "a27963487e346338e4c216bd4fbb9e2a", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "c22901e06e88a55cce0b4e08bbf41a4c", @@ -4096,14 +4096,14 @@ "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "852fe46c736082611a831a618923c241", "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "36fbda7829ed5c2862c34feb09b03402", "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "852fe46c736082611a831a618923c241", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "23dbca6f6f4c8b9061e68af17d79791b", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "639bb72656fb6f5b21ac525b9098854a", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "d0a0820657e11771d1e393d47af23c17", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "62f9d32dcc6c74421f1a3f88abf07777", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "2d38cd1723c7b1a9a1b19d206d5a17a5", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "8e4304d0b16fa16038fc1660eb06c350", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "08120b7a6b3845cf729c1defcc6e90ec", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "f5d59b0bce6cb0e43da92a5863bb963c", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "38b4b5b85a9bafdb76222d0f0c962b06", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "9a8af3d217bcb0bacfaed4c30dd5f42e", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "6d10ca306f60d66efb4942636e4955d6", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "1c65d36e4420ed79380dc8c041c94a8b", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "9b1b72f3d41c89a6b06288be63e8f40a", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "e0f2eb8ea024bc88e999b9dc16317fd4", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "42be1225757328f432d91de950444ba0", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "05bc2832cc0c9fba308668fc1a6d3b0f", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/enums.py": "28323912b56ec07701eda3d41a6a4101", "src/ballistica/base/mgen/pyembed/binding_base.inc": "72bfed2cce8ff19741989dec28302f3f", diff --git a/CHANGELOG.md b/CHANGELOG.md index 9260d82e..0f3ac4a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.30 (build 21630, api 8, 2023-11-29) +### 1.7.30 (build 21636, api 8, 2023-11-30) - Continued work on the big 1.7.28 update. - Got the Android version back up and running. There's been lots of cleanup and simplification on the Android layer, cleaning out years of cruft. This should @@ -19,6 +19,11 @@ effects such as the app continuing to play audio when it should not be. - (build 21626) Fixed a bug where click/tap locations were incorrect on some builds when tv-border was on (Thanks for the heads-up Loup(Dliwk's fan)!). +- (build 21631) Fixes an issue where '^^^^^^^^^^^^^' lines in stack traces could + get chopped into tiny bits each on their own line in the dev console. +- Fixed a longstanding issue where multiple key presses simultaneously could + cause multiple windows to pop up where only one is expected. Please holler if + you still see this problem happening anywhere. ### 1.7.29 (build 21619, api 8, 2023-11-21) diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 1c0c3867..82c27c87 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -52,7 +52,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 21630 +TARGET_BALLISTICA_BUILD = 21636 TARGET_BALLISTICA_VERSION = '1.7.30' diff --git a/src/assets/ba_data/python/bauiv1lib/mainmenu.py b/src/assets/ba_data/python/bauiv1lib/mainmenu.py index cacb3fdf..7e6ca3d4 100644 --- a/src/assets/ba_data/python/bauiv1lib/mainmenu.py +++ b/src/assets/ba_data/python/bauiv1lib/mainmenu.py @@ -311,8 +311,8 @@ class MainMenuWindow(bui.Window): else self._confirm_end_game ), ) - # Assume we're in a client-session. else: + # Assume we're in a client-session. bui.buttonwidget( parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), @@ -360,7 +360,6 @@ class MainMenuWindow(bui.Window): tilt_scale=0.0, draw_controller=store_button, ) - self._tdelay += self._t_delay_inc else: self._store_button = None diff --git a/src/ballistica/base/graphics/graphics.cc b/src/ballistica/base/graphics/graphics.cc index f6802563..c5d920d3 100644 --- a/src/ballistica/base/graphics/graphics.cc +++ b/src/ballistica/base/graphics/graphics.cc @@ -615,7 +615,7 @@ void Graphics::FadeScreen(bool to, millisecs_t time, PyObject* endcall) { Log(LogLevel::kWarning, "2 fades overlapping; running first fade-end-call early."); } - fade_end_call_->Schedule(); + fade_end_call_->ScheduleOnce(); fade_end_call_.Clear(); } set_fade_start_on_next_draw_ = true; @@ -1021,7 +1021,7 @@ void Graphics::DrawFades(FrameDef* frame_def) { } else { fade_ = 0; if (!was_done && fade_end_call_.Exists()) { - fade_end_call_->Schedule(); + fade_end_call_->ScheduleOnce(); fade_end_call_.Clear(); } } diff --git a/src/ballistica/base/python/methods/python_methods_app.cc b/src/ballistica/base/python/methods/python_methods_app.cc index 44055fd7..8815316c 100644 --- a/src/ballistica/base/python/methods/python_methods_app.cc +++ b/src/ballistica/base/python/methods/python_methods_app.cc @@ -279,7 +279,7 @@ static auto PyPushCall(PyObject* self, PyObject* args, PyObject* keywds) if (!g_base->InLogicThread()) { throw Exception("You must use from_other_thread mode."); } - Object::New(call_obj)->Schedule(); + Object::New(call_obj)->ScheduleOnce(); } Py_RETURN_NONE; BA_PYTHON_CATCH; diff --git a/src/ballistica/base/python/support/python_context_call.cc b/src/ballistica/base/python/support/python_context_call.cc index a37ddffb..4be03012 100644 --- a/src/ballistica/base/python/support/python_context_call.cc +++ b/src/ballistica/base/python/support/python_context_call.cc @@ -125,45 +125,83 @@ void PythonContextCall::Schedule() { Object::Ref ref(this); assert(base::g_base); + schedule_count_++; base::g_base->logic->event_loop()->PushCall([ref] { assert(ref.Exists()); + ref->schedule_count_--; + assert(ref->schedule_count_ >= 0); ref->Run(); }); } +void PythonContextCall::ScheduleOnce() { + if (schedule_count_ > 0) { + return; + } + Schedule(); +} void PythonContextCall::Schedule(const PythonRef& args) { // Since we're mucking with Object::Refs, need to limit to logic thread. BA_PRECONDITION(g_base->InLogicThread()); Object::Ref ref(this); assert(base::g_base); + schedule_count_++; base::g_base->logic->event_loop()->PushCall([ref, args] { assert(ref.Exists()); + ref->schedule_count_--; + assert(ref->schedule_count_ >= 0); ref->Run(args); }); } +void PythonContextCall::ScheduleOnce(const PythonRef& args) { + if (schedule_count_ > 0) { + return; + } + Schedule(args); +} void PythonContextCall::ScheduleWeak() { // Since we're mucking with Object::WeakRefs, need to limit to logic thread. BA_PRECONDITION(g_base->InLogicThread()); Object::WeakRef ref(this); assert(base::g_base); + schedule_count_++; base::g_base->logic->event_loop()->PushCall([ref] { if (auto* call = ref.Get()) { + call->schedule_count_--; + assert(call->schedule_count_ >= 0); call->Run(); } }); } +void PythonContextCall::ScheduleWeakOnce() { + if (schedule_count_ > 0) { + return; + } + ScheduleWeak(); +} + void PythonContextCall::ScheduleWeak(const PythonRef& args) { // Since we're mucking with Object::WeakRefs, need to limit to logic thread. BA_PRECONDITION(g_base->InLogicThread()); Object::WeakRef ref(this); assert(base::g_base); + schedule_count_++; base::g_base->logic->event_loop()->PushCall([ref, args] { if (auto* call = ref.Get()) { + call->schedule_count_--; + assert(call->schedule_count_ >= 0); call->Run(args); } }); } +void PythonContextCall::ScheduleWeakOnce(const PythonRef& args) { + if (schedule_count_ > 0) { + return; + } + ScheduleWeak(args); +} + } // namespace ballistica::base diff --git a/src/ballistica/base/python/support/python_context_call.h b/src/ballistica/base/python/support/python_context_call.h index e753740f..1c99d3bc 100644 --- a/src/ballistica/base/python/support/python_context_call.h +++ b/src/ballistica/base/python/support/python_context_call.h @@ -11,10 +11,10 @@ namespace ballistica::base { -// A callable and ballistica context-state wrapped up in a convenient package. -// Handy for use with user-submitted callbacks, as it restores context -// state from when it was created and prints various useful bits of context -// info on exceptions. +// A callable and ballistica context-state wrapped up in a convenient +// package. Handy for use with user-submitted callbacks, as it restores +// context state from when it was created and prints various useful bits of +// context info on exceptions. class PythonContextCall : public Object { public: static auto current_call() -> PythonContextCall* { return current_call_; } @@ -37,35 +37,65 @@ class PythonContextCall : public Object { auto file_loc() const -> const std::string& { return file_loc_; } void PrintContext(); - /// Run in an upcoming cycle of the logic thread. - /// Must be called from the logic thread. - /// This form creates a strong-reference so the context_ref-call is guaranteed - /// to exist until run. + /// Run in an upcoming cycle of the logic thread. Must be called from the + /// logic thread. This form creates a strong-reference so the + /// context_ref-call is guaranteed to exist until run. void Schedule(); - /// Run in an upcoming cycle of the logic thread with provided args. - /// Must be called from the logic thread. - /// This form creates a strong-reference so the context_ref-call is guaranteed - /// to exist until run. + + /// Schedule only if this instance is not already scheduled. Generally a + /// good idea unless you know you need multiple runs scheduled. Avoids + /// problems such as UIs expecting to be activated only once getting + /// activated twice due to two simultenous key presses. + void ScheduleOnce(); + + /// Run in an upcoming cycle of the logic thread with provided args. Must + /// be called from the logic thread. This form creates a strong-reference + /// so the context_ref-call is guaranteed to exist until run. void Schedule(const PythonRef& args); - /// Run in an upcoming cycle of the logic thread. - /// Must be called from the logic thread. - /// This form creates a weak-reference and is a no-op if the context_ref-call - /// is destroyed before its scheduled run. + + /// Schedule only if this instance is not already scheduled. Generally a + /// good idea unless you know you need multiple runs scheduled. Avoids + /// problems such as UIs expecting to be activated only once getting + /// activated twice due to two simultenous key presses. + void ScheduleOnce(const PythonRef& args); + + /// Run in an upcoming cycle of the logic thread. Must be called from the + /// logic thread. This form creates a weak-reference and is a no-op if the + /// context_ref-call is destroyed before its scheduled run. void ScheduleWeak(); - /// Run in an upcoming cycle of the logic thread with provided args. - /// Must be called from the logic thread. - /// This form creates a weak-reference and is a no-op if the context_ref-call - /// is destroyed before its scheduled run. + + /// Schedule weakly only if this instance is not already scheduled. + /// Generally a good idea unless you know you need multiple runs + /// scheduled. Avoids problems such as UIs expecting to be activated only + /// once getting activated twice due to two simultenous key presses. + void ScheduleWeakOnce(); + + /// Run in an upcoming cycle of the logic thread with provided args. Must + /// be called from the logic thread. This form creates a weak-reference + /// and is a no-op if the context_ref-call is destroyed before its + /// scheduled run. void ScheduleWeak(const PythonRef& args); + /// Schedule weakly only if this instance is not already scheduled. + /// Generally a good idea unless you know you need multiple runs + /// scheduled. Avoids problems such as UIs expecting to be activated only + /// once getting activated twice due to two simultenous key presses. + void ScheduleWeakOnce(const PythonRef& args); + + auto IsScheduled() const { + assert(g_base->InLogicThread()); + return schedule_count_ > 0; + } + private: void GetTrace(); // we try to grab basic trace info - std::string file_loc_; + int line_{}; - bool dead_ = false; + int schedule_count_{}; + bool dead_{}; + std::string file_loc_; PythonRef object_; base::ContextRef context_state_; - // base::Context* context_target_sanity_test_{}; static PythonContextCall* current_call_; }; diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index 8e5c52ad..38e7096c 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int { namespace ballistica { // These are set automatically via script; don't modify them here. -const int kEngineBuildNumber = 21630; +const int kEngineBuildNumber = 21636; const char* kEngineVersion = "1.7.30"; const int kEngineApiVersion = 8; diff --git a/src/ballistica/ui_v1/python/ui_v1_python.cc b/src/ballistica/ui_v1/python/ui_v1_python.cc index f12321b0..f4157594 100644 --- a/src/ballistica/ui_v1/python/ui_v1_python.cc +++ b/src/ballistica/ui_v1/python/ui_v1_python.cc @@ -115,7 +115,7 @@ void UIV1Python::InvokeStringEditor(PyObject* string_edit_adapter_instance) { PythonRef::kSteal); Object::New( objs().Get(ObjID::kOnScreenKeyboardClass)) - ->Schedule(args); + ->ScheduleOnce(args); } void UIV1Python::LaunchStringEditOld(TextWidget* w) { @@ -131,7 +131,7 @@ void UIV1Python::LaunchStringEditOld(TextWidget* w) { PythonRef::kSteal); Object::New( objs().Get(ObjID::kOnScreenKeyboardClass)) - ->Schedule(args); + ->ScheduleOnce(args); } void UIV1Python::InvokeQuitWindow(QuitType quit_type) { diff --git a/src/ballistica/ui_v1/widget/button_widget.cc b/src/ballistica/ui_v1/widget/button_widget.cc index 29c6db6a..7b824db1 100644 --- a/src/ballistica/ui_v1/widget/button_widget.cc +++ b/src/ballistica/ui_v1/widget/button_widget.cc @@ -562,7 +562,7 @@ void ButtonWidget::DoActivate(bool is_repeat) { if (auto* call = on_activate_call_.Get()) { // Call this in the next cycle (don't want to risk mucking with UI from // within a UI loop.) - call->ScheduleWeak(); + call->ScheduleWeakOnce(); return; } } diff --git a/src/ballistica/ui_v1/widget/check_box_widget.cc b/src/ballistica/ui_v1/widget/check_box_widget.cc index 7cc44a6a..f252870a 100644 --- a/src/ballistica/ui_v1/widget/check_box_widget.cc +++ b/src/ballistica/ui_v1/widget/check_box_widget.cc @@ -247,7 +247,7 @@ void CheckBoxWidget::Activate() { // Call this in the next cycle (don't want to risk mucking with UI from // within a UI loop) - call->ScheduleWeak(args); + call->ScheduleWeakOnce(args); } } diff --git a/src/ballistica/ui_v1/widget/container_widget.cc b/src/ballistica/ui_v1/widget/container_widget.cc index e88af6b6..e47bbb17 100644 --- a/src/ballistica/ui_v1/widget/container_widget.cc +++ b/src/ballistica/ui_v1/widget/container_widget.cc @@ -347,7 +347,7 @@ auto ContainerWidget::HandleMessage(const base::WidgetMessage& m) -> bool { // Call this in the next cycle (don't wanna risk mucking with UI from // within a UI loop). - call->ScheduleWeak(); + call->ScheduleWeakOnce(); } else { OnCancelCustom(); } @@ -631,7 +631,7 @@ auto ContainerWidget::HandleMessage(const base::WidgetMessage& m) -> bool { if (!claimed && on_outside_click_call_.Exists()) { // Call this in the next cycle (don't wanna risk mucking with UI from // within a UI loop). - on_outside_click_call_->ScheduleWeak(); + on_outside_click_call_->ScheduleWeakOnce(); } // Always claim if they want. @@ -1071,7 +1071,7 @@ void ContainerWidget::Activate() { if (auto* call = on_activate_call_.Get()) { // Call this in the next cycle (don't wanna risk mucking with UI from within // a UI loop). - call->ScheduleWeak(); + call->ScheduleWeakOnce(); } } @@ -1182,6 +1182,7 @@ void ContainerWidget::SetTransition(TransitionType t) { dynamics_update_time_millisecs_ = display_time_millisecs; transitioning_ = true; transitioning_out_ = true; + ignore_input_ = true; } else { // Calculate the screen size in our own local space - we'll // animate an offset to slide on/off screen. diff --git a/src/ballistica/ui_v1/widget/text_widget.cc b/src/ballistica/ui_v1/widget/text_widget.cc index 67474f50..687c1689 100644 --- a/src/ballistica/ui_v1/widget/text_widget.cc +++ b/src/ballistica/ui_v1/widget/text_widget.cc @@ -592,7 +592,7 @@ void TextWidget::Activate() { if (auto* call = on_activate_call_.Get()) { // Call this in the next cycle (don't wanna risk mucking with UI from // within a UI loop). - call->ScheduleWeak(); + call->ScheduleWeakOnce(); } // Bring up an editor if applicable. @@ -720,7 +720,7 @@ auto TextWidget::HandleMessage(const base::WidgetMessage& m) -> bool { claimed = true; // Call this in the next cycle (don't wanna risk mucking with UI // from within a UI loop) - call->ScheduleWeak(); + call->ScheduleWeakOnce(); } } break; diff --git a/src/ballistica/ui_v1/widget/widget.cc b/src/ballistica/ui_v1/widget/widget.cc index 6b8464fc..257d2198 100644 --- a/src/ballistica/ui_v1/widget/widget.cc +++ b/src/ballistica/ui_v1/widget/widget.cc @@ -88,7 +88,7 @@ void Widget::SetSelected(bool s, SelectionCause cause) { if (selected_ && on_select_call_.Exists()) { // Call this in the next cycle (don't wanna risk mucking // with UI from within a UI loop). - on_select_call_->ScheduleWeak(); + on_select_call_->ScheduleWeakOnce(); } } diff --git a/tools/efro/log.py b/tools/efro/log.py index c397b7ff..77b89996 100644 --- a/tools/efro/log.py +++ b/tools/efro/log.py @@ -450,6 +450,11 @@ class LogHandler(logging.Handler): def file_write(self, name: str, output: str) -> None: """Send raw stdout/stderr output to the logger to be collated.""" + # Note to self: it turns out that things like '^^^^^^^^^^^^^^' + # lines in stack traces get written as lots of individual '^' + # writes. It feels a bit dirty to be pushing a deferred call to + # another thread for each character. Perhaps should do some sort + # of basic accumulation here? self._event_loop.call_soon_threadsafe( tpartial(self._file_write_in_thread, name, output) ) @@ -509,12 +514,18 @@ class LogHandler(logging.Handler): traceback.print_exc(file=self._echofile) async def _ship_chunks_task(self, name: str) -> None: + # Note: it's important we sleep here for a moment. Otherwise, + # things like '^^^^^^^^^^^^' lines in stack traces, which come + # through as lots of individual '^' writes, tend to get broken + # into lots of tiny little lines by us. + await asyncio.sleep(0.01) self._ship_file_chunks(name, cancel_ship_task=False) def _ship_file_chunks(self, name: str, cancel_ship_task: bool) -> None: # Note: Raw print input generally ends in a newline, but that is - # redundant when we break things into log entries and results - # in extra empty lines. So strip off a single trailing newline. + # redundant when we break things into log entries and results in + # extra empty lines. So strip off a single trailing newline if + # one is present. text = ''.join(self._file_chunks[name]).removesuffix('\n') self._emit_entry(